洛谷P1629 邮递员送信(反向建图)
题目链接:https://www.luogu.com.cn/problem/P1629
蛮有意思的一道题目
说实话第一见这种题真的不太好想。
读题发现,
并且重点词语被出题人贴心的标黑了,“运送每件物品过后必须返回邮局”,
这要求我们走完一遍最短路之后还要在折回去,也就是说,第一次最短路是从起点到终点,而第二次最短路是从终点到起点。
可以这样处理,如果是要求从终点到起点的话,有两种处理思路:
1.新建一张图,储存起点到终点的时候顺带储存终点到起点,然后进行最短路,
事实证明,这样是可行的,我第一次是这么做的,并且也A了,但这样难免会有些麻烦,
因为这样如此,在写一个e的同时也要写一个e2,搞不好还要写俩最短路,当然,我写了一个,过了,但这样不是稳妥和高效的做法。
说不定下一次加强数据就崩掉了。
2.比较稳妥的做法是这样:
前半部分是规规矩矩的建图,初始化,最短路,求和,
后半部分我们可以这样:
在求完正向最短路之后,
我们对起点和终点进行位置互换,当然权值是不必要变得,因为正着走和反着走都是走那一条路。
所以说只需要变起点和终点位置即可,
那这样我们仅仅需要挨个调换他们的位置,这个用交换函数就可以做到,
交换完成之后在跑一边,挨个求多源路径,总和就是
正着跑和反着跑的最短路径
这个题还需要注意的是,这个图是单边的而不是双边的,因为“这个邮递员每次只能带一样东西,”
这样来看,我们就省去双边建图和图边双扩的麻烦,用一个循环来建图就可以了。
Talk is cheap. Show me the code.
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,m; 4 const int num=100010; 5 const int INF=0x3f3f3f3f; 6 struct edge 7 { 8 int u; 9 int v; 10 int w; 11 }e[num]; 12 int ans;//最短路径 13 int dis[num];//从终点到起点的距离 14 void over()//反转函数 15 { 16 for(register int i=0;i<m;i++) 17 swap(e[i].u,e[i].v); 18 } 19 void bellman()//常规bellman-Ford 20 { 21 int s=1; 22 for(register int i=1;i<=n;i++) 23 dis[i]=INF; 24 dis[s]=0; 25 for(register int k=1;k<=n;k++) 26 { 27 for(register int i=0;i<m;i++) 28 { 29 int a=e[i].u; 30 int b=e[i].v; 31 if(dis[a]>dis[b]+e[i].w) 32 { 33 dis[a]=dis[b]+e[i].w; 34 } 35 } 36 } 37 } 38 int main() 39 { 40 std::ios::sync_with_stdio(false); 41 cin>>n>>m; 42 for(register int i=0;i<m;i++)//单边输入,这个题目考察单边,双边就要用cnt了 43 { 44 int a,b,c; 45 cin>>a>>b>>c; 46 e[i].u=a; 47 e[i].v=b; 48 e[i].w=c; 49 } 50 bellman();//正向跑图 51 for(register int i=1;i<=n;i++)//累加权值 52 { 53 ans+=dis[i]; 54 } 55 over();//反转图 56 bellman();//反向跑图 57 for(register int i=1;i<=n;i++)//累加权值 58 ans+=dis[i]; 59 cout<<ans<<endl; 60 return 0; 61 }
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/16205391.html