原題:
You are a political prisoner in jail. Things are looking grim, but fortunately, your jailmate has come up with an escape plan. He has found a way for both of you to get out of the cell and run through the city to the train station, where you will leave the country. Your friend will escape first and run along the streets of the city to the train station. He will then call you from there on your cellphone (which somebody smuggled in to you inside a cake), and you will start to run to the same train station. When you meet your friend there, you will both board a train and be on your way to freedom.Your friend will be running along the streets during the day, wearing his jail clothes, so people will notice. This is why you can not follow any of the same streets that your friend follows - the authorities may be waiting for you there. You have to pick a completely different path (although you may run across the same intersections as your friend). What is the earliest time at which you and your friend can board a train?
Problem, in short
Given a weighed, undirected graph, find the shortest path from S to T and back without using the same edge twice.
Input
The input will contain several test cases. Each test case will begin with an integer n (2 ≤ n ≤ 100)
— the number of nodes (intersections). The jail is at node number 1, and the train station is at node number n. The next line will contain an integer m — the number of streets. The next m lines will describe the m streets. Each line will contain 3 integers — the two nodes connected by the street and the time it takes to run the length of the street (in seconds). No street will be longer than 1000 or shorter than 1. Each street will connect two different nodes. No pair of nodes will be directly connected by more than one street. The last test case will be followed by a line containing zero.
Output
For each test case, output a single integer on a line by itself — the number of seconds you and your friend need between the time he leaves the jail cell and the time both of you board the train. (Assume that you do not need to wait for the train — they leave every second.) If there is no solution, print ‘Back to jail’.
Sample Input
2
1
1 2 999
3
3
1 3 10
2 1 20
3 2 50
9
12
1 2 10
1 3 10
1 4 10
2 5 10
3 5 10
4 5 10
5 7 10
6 7 10
7 8 10
6 9 10
7 9 10
8 9 10
0
Sample Output
Back to jail
80
Back to jail
中文:
給你一個帶權無向圖,讓你找從節點1到節點n,然後再從節點n走回節點1所用的費用最小。
#include<bits/stdc++.h>using namespace std;const int maxn=10001;int mark;struct Edge{ int from,to,cap,flow,cost; Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}};struct MCMF{ int n,m; vector<Edge> edges; vector<int> G[maxn]; int inq[maxn]; int d[maxn]; int p[maxn]; int a[maxn]; void init(int n) { this->n=n; for(int i=1;i<=n;i++) G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap,int cost) { edges.push_back(Edge(from,to,cap,0,cost)); edges.push_back(Edge(to,from,0,0,-cost)); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s,int t,int& flow,long long& cost) { for(int i=1;i<=n;i++) d[i]=INT_MAX; memset(inq,0,sizeof(inq)); d[s]=0; inq[s]=1; p[s]=0; a[s]=INT_MAX; queue<int> Q; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); inq[u]=0; for(int i=0;i<G[u].size();i++) { Edge& e=edges[G[u][i]]; if(e.cap>e.flow&&d[e.to]>d[u]+e.cost) { d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]) { Q.push(e.to); inq[e.to]=1; } } } } if(d[t]==INT_MAX) return false; flow+=a[t]; cost+=(long long )d[t]*(long long)a[t]; for(int u=t;u!=s;u=edges[p[u]].from) { edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } return true; } int MincostMaxflow(int s,int t,long long& cost) { int flow = 0; cost=0; int road=0; while(BellmanFord(s,t,flow,cost)) { road++; if(road==2) break; } if(road==2) mark=true; return flow; }};MCMF M;int main(){ ios::sync_with_stdio(false); int n,m; while(cin>>n,n) { M.init(n); mark=false; cin>>m; for(int i=1;i<=m;i++) { int f,t,c; cin>>f>>t>>c; M.AddEdge(f,t,1,c); M.AddEdge(t,f,1,c); } long long cost=0; M.MincostMaxflow(1,n,cost); if(!mark) cout<<"Back to jail"<<endl; else cout<<cost<<endl; } return 0;}
解答:
這是我第一道最小費用最大流的題目,剛開始被這道題的名字給忽悠了,一直以為是最短路問題,但是想了半天也想不出怎麼解(貌似可以用次短路徑來解決)。上網上一搜,結果一看是網路流的題目-_-。
這裡把圖當中的所有邊上的流量都設定為1,由於是無向圖,所以需要在兩個節點之間建立兩條相同的邊。
題目中要求從起點走到終點,再從終點回到起點,這裡要用到網路流處理當中的特性,如果走過某一條邊,那麼這條變上要增加對應的流量,同時反向邊要減少對應的流量。這也是網路流當中的精華和核心部分,也是網路流演算法為什麼能解決這個問題的根本所在。
現在起點是s終點是t,如果第一條路徑走的是s->a->b->c->t,那麼邊上的流量就會發生改變,第二次搜尋到的路徑可能是s->b->a->d->t,那麼兩條路徑權值和起來就是s->c->t加上s->d->t的值的和。所以,使用最小費用最大流演算法可以解決此問題,相當於從起點找兩條到終點的最小費用的增廣路徑,兩次的費用和就是答案。