bzoj4289 PA2012 Tax——点边转化

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289

好巧妙的转化!感觉自己难以想出来...

参考了博客:https://blog.csdn.net/reverie_mjp/article/details/52134142

把边变成点,相互之间连边;

原图上由一个点连接的许多边之间应该通过连新边达到题目要求的取较大值的目的;

做法就是把一个原图点的关联边排序,然后较小的边向较大的边连边权为差值的新边,较大的边连回去边权为0的新边;

那么如果原图上要走 a,b 两条边,新图上两条边(点)之间有代价,付出代价等价于取较大值;

还要注意原图是无向图,连新边时要连向自己的反向边,因为新图连的都是有向边,所以这样可以实现原图中走一条边移动的效果,也就是两个原图点的关联边之间也有联系;

再建立一个源点和汇点,1号点的关联边都连向源点,连向 n 号点的边都连向汇点;

然后从源点开始跑最短路,到汇点的最短路就是答案。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=1e5+5,maxm=4e5+5;
int n,m,head[maxn],xt=1,hd[maxm],ct=1,tmp[maxm],t,S,T;
ll dis[maxm];
bool vis[maxm];
priority_queue<pair<ll,int> >q;//ll!!!
struct N{
    int to,nxt,w;
    N(int t=0,int n=0,int w=0):to(t),nxt(n),w(w) {}
}ed[maxm<<3],edge[maxm];
void add1(int x,int y,int w){edge[++xt]=N(y,head[x],w); head[x]=xt;}
void add2(int x,int y,int w){ed[++ct]=N(y,hd[x],w); hd[x]=ct;}
bool cmp(int x,int y){return edge[x].w<edge[y].w;}
void dijkstra()
{
    memset(dis,0x3f,sizeof dis);
    dis[S]=0; q.push(make_pair(0,S));
    while(q.size())
    {
        int x=q.top().second; q.pop();
        if(vis[x])continue;
        vis[x]=1;
        for(int i=hd[x],u;i;i=ed[i].nxt)
        {
            if(dis[u=ed[i].to]>dis[x]+ed[i].w)
            {
                dis[u]=dis[x]+ed[i].w;
                q.push(make_pair(-dis[u],u));
            }
        }
    }

}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,x,y,z;i<=m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add1(x,y,z); add1(y,x,z);
    }
    S=1; T=2*(m+1);
    for(int i=1;i<=n;i++)
    {
        t=0;
        for(int j=head[i];j;j=edge[j].nxt)tmp[++t]=j;
        sort(tmp+1,tmp+t+1,cmp);
        for(int j=1;j<=t;j++)
        {
            if(i==1)add2(S,tmp[j],edge[tmp[j]].w);
            if(edge[tmp[j]].to==n)add2(tmp[j],T,edge[tmp[j]].w);
            add2(tmp[j]^1,tmp[j],edge[tmp[j]].w);//!
            if(j<t)
            {
                add2(tmp[j],tmp[j+1],edge[tmp[j+1]].w-edge[tmp[j]].w);
                add2(tmp[j+1],tmp[j],0);
            }
        }
    }
    dijkstra();
    printf("%lld\n",dis[T]);
    return 0;
}

原文地址:https://www.cnblogs.com/Zinn/p/9326302.html

时间: 2024-08-05 11:15:19

bzoj4289 PA2012 Tax——点边转化的相关文章

BZOJ4289 : PA2012 Tax

一个直观的想法是把每条边拆成两条有向边,同时每条有向边是新图中的一个点.对于两条边a->b与b->c,两点之间连有向边,费用为两条边费用的最大值.然后新建源点S与汇点T,由S向所有起点为1的边连边,T接受所有终点为n的边,那么答案就是S到T的最短路. 这样子的边数为$O(m^2)$,不能承受. 考虑枚举中转点x,将所有与它有关的边按费用从小到大排序.对于每条边,从以x为终点的点向以x为起点的点连边,费用为该边的费用.从以x为起点的点向下一条边连边,费用为两条边费用的差值,向上一条边连边,费用为

【BZOJ-4289】Tax 最短路 + 技巧建图

4289: PA2012 Tax Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 168  Solved: 69[Submit][Status][Discuss] Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权 N<=100000 M<=200000 Input Output Sample I

【Bzoj4289】PA2012 Tax(Dijkstra+技巧建图)

Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权 N<=100000 M<=200000 Solution 这题关键在于化边为点,把无向边拆成2条有向边 考虑最直白的一种建图方法,对于每一个点u,它的每一条入边向所有出边连边 但这样边数太多了,最坏是\(M^2\)条边,不可行 考虑用差值来建图,每条出边向第一条比它大的出边连一条权值为权差值的

【PA2012】【BZOJ4289】Tax

Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值.求从起点1到点N的最小代价. 起点的代价是离开起点的边的边权.终点的代价是进入终点的边的边权 N<=100000 M<=200000 Input Output Sample Input 4 5 1 2 5 1 3 2 2 3 1 2 4 4 3 4 8 Sample Output 12 HINT Source 一眼能看出是最短路变种.. 可是我仅仅会n^2建图T_T n^2建图就是边

●BZOJ 4289 PA2012 Tax

●赘述题目 算了,题目没有重复的必要. 注意理解:对答案造成贡献的是每个点,就是了. 举个栗子: 对于如下数据: 2 1 1 2 1 答案是 2: ●题解 方法:建图(难点)+最短路. 先来几个链接:(他们为我解题提供了思路,但有些部分看得我有点mengbi) ●http://blog.csdn.net/pure_w/article/details/55060079 ●http://www.cnblogs.com/clrs97/p/5046933.html 建图: 1.把原图的双向边拆成两条单向

BZOJ.4289.PA2012 Tax(思路 Dijkstra)

题目链接 \(Description\) 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权. \(Solution\) 最直接的方法是把每条边作为一个点,对于连接同一个点的两条边连一条新边,最后把连接1和n的点分别连S.T,跑最短路 但这样边数是O(m^2)的 对于路径上相邻两条边\((i,j,v1)\)和\((j,k,v2)\),v1<v2,考虑如何构图把v1比v2

BZOJ 4289: PA2012 Tax

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 755  Solved: 240[Submit][Status][Discuss] Description 给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权 N<=100000 M<=200000 Input Output Sample Input 4 5 1 2 5 1

[PA2012] Tax

传送门:>Here< 题意:给出一个N个点M条边的无向图,经过一个点的代价是进入和离开这个点的两条边的边权的较大值,求从起点1到点N的最小代价.起点的代价是离开起点的边的边权,终点的代价是进入终点的边的边权N<=100000 M<=200000 解题思路 不免要吐槽一下这题的数据,久调一下午无果与标程对拍没有任何差错不知道为什么就是WA 既然极限数据已经和标程拍上了那么权当出了吧…… 不过还是一道好题 首先考虑这道题暴力的做法——将每条边作为新图的点,然后枚举原图的点,遍历一遍这个

bzoj 4289 TAX —— 点边转化

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4289 把边转化成点,同一个原有点相连的边中,边权小的向大的连差值的边,大的向小的连0的边: 一开始想的是给每个新点记一个点权是这个点(边)原来的权,走到它时先加上点权,因为要在原图上经过这条边还是要花费边权: 但是这样在原图中的边之间转移时会把它们的边权都加上,就不对了: 所以应该是把原图的边进一步拆成两个点,两端点的集合各加入一个,这两点之间连原边权的边: 题目上什么也没说...总之 d