10.16T5 最小环+拆点最短路
Description
2012伦敦奥运会就要来了,此次伦敦奥运的火炬将不再进行全球传递,也就是只在本国英国传递。伦敦奥组委计划将火炬传遍英国的各个角落,这下可苦了某些城市的市长,由于欧债危机,他们实在无钱支付火炬传递需要的开销。于是设计一条花费最小的火炬传递路线势在必行。X市的格局很神奇,这个市是一个类似威尼斯的水城,共有n个岛,并且有m条桥连接着它们,这些桥在火炬传递期间只能单向行进,通过每座桥都有一定的费用(包括环境布置等)。火炬传递的路线必须是一个环,也就是说,你可以任意选择一个岛出发,最后必须回到这个岛。现在请你找出花费最小的一条火炬传递路线。
Input
输入第一行包含两个整数n,m,表示岛屿个数和桥的个数。
接下来m行,第i行两个整数,x,y, c,表示可以从岛x经过第i座桥到达岛y,花费为c。
接下来m行,第i行两个整数,x,y, c,表示可以从岛x经过第i座桥到达岛y,花费为c。
Output
输出一行,最小花费。
Sample Input
10 15
8 9 1
6 2 10
2 4 5
3 1 5
1 4 3
6 7 10
2 9 9
1 5 8
10 6 5
3 10 4
8 6 8
6 5 4
6 4 8
3 2 9
7 8 5
Sample Output
23
Hint
对于50%的数据n<=200, m<=2000
对于100%的数据n<=1000, m<=10000
对于100%的数据n<=1000, m<=10000
这题肯定考的是最小环,然而看数据范围直接求解的话好像会爆炸,那么实际上我们求的是一个点回到另一个点的最短路
所以我们就可以想到拆点这个操作,我们把每个点拆成出发的点和到达的点,连边的时候不仅仅要正常按照a->b连边,同时还要连上a->b'的边
最后我们就可以枚举每一个图中的点然后对两个点之间跑一个最短路,再次进行比较就可以了
所以遇到环类问题还是要考虑拆点吧。。。emmm,算是一个有用的方法了
code:
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 #include<cstring> 5 #include<algorithm> 6 #define N 1000005 7 using namespace std; 8 struct node{ 9 int u,v,w; 10 }e[N]; 11 int first[N],nxt[N],cnt; 12 void add(int u,int v,int w){ 13 e[++cnt].u=u; 14 e[cnt].v=v; 15 e[cnt].w=w; 16 nxt[cnt]=first[u]; 17 first[u]=cnt; 18 } 19 int dis[N],vis[N]; 20 void spfa(int s){ 21 queue<int>q; 22 memset(vis,0,sizeof vis); 23 memset(dis,0x3f3f3f3f,sizeof dis); 24 vis[s]=1; 25 dis[s]=0; 26 q.push(s); 27 while(!q.empty()){ 28 int u=q.front(); 29 q.pop(); 30 vis[u]=0; 31 for(int i=first[u];i;i=nxt[i]){ 32 int v=e[i].v; 33 if(dis[v]>dis[u]+e[i].w){ 34 dis[v]=dis[u]+e[i].w; 35 if(!vis[v]){ 36 vis[v]=1; 37 q.push(v); 38 } 39 } 40 } 41 } 42 } 43 int main(){ 44 int n,m; 45 cin>>n>>m; 46 for(int i=1;i<=m;i++){ 47 int u,v,w; 48 cin>>u>>v>>w; 49 add(u,v,w); 50 add(u,v+n,w); 51 } 52 int min0=99999999; 53 for(int i=1;i<=n;i++){ 54 spfa(i); 55 min0=min(min0,dis[i+n]); 56 } 57 cout<<min0; 58 return 0; 59 }
over