POJ 2135 Farm Tour
Farm Tour
Time Limit: 1000ms
Memory Limit: 65536KB
This problem will be judged on PKU. Original ID: 213564-bit integer IO format: %lld Java class name: Main
When FJ's friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of which contains his house and the Nth of which contains the big barn. A total M (1 <= M <= 10000) paths that connect the fields in various ways. Each path connects two different fields and has a nonzero length smaller than 35,000.
To show off his farm in the best way, he walks a tour that starts at his house, potentially travels through some fields, and ends at the barn. Later, he returns (potentially through some fields) back to his house again.
He wants his tour to be as short as possible, however he doesn't want to walk on any given path more than once. Calculate the shortest tour possible. FJ is sure that some tour exists for any given farm.
To show off his farm in the best way, he walks a tour that starts at his house, potentially travels through some fields, and ends at the barn. Later, he returns (potentially through some fields) back to his house again.
He wants his tour to be as short as possible, however he doesn't want to walk on any given path more than once. Calculate the shortest tour possible. FJ is sure that some tour exists for any given farm.
Input
* Line 1: Two space-separated integers: N and M.
* Lines 2..M+1: Three space-separated integers that define a path: The starting field, the end field, and the path's length.
* Lines 2..M+1: Three space-separated integers that define a path: The starting field, the end field, and the path's length.
Output
A single line containing the length of the shortest tour.
Sample Input
4 5 1 2 1 2 3 1 3 4 1 1 3 2 2 4 2
Sample Output
6
Source
解题:最小费用最大流。建模:求去回的最短路。每条路最多只访问一次。既然要去一次,还要回一次,不重复。路径长度刚好看作费用。每条路的容量为1。(超级源点到1的费用为0,容量为2.终点到超级汇点的费用也为0,容量为2.)为了容量设为1呢。还记得大明湖畔的增广路么?网络流的一种算法不就是寻找增广路么?可想,每次从超级源点出发,到超级汇点找到一条增广路。然后把该路上的流量减1.因为都是1,所以最小就是1.表示去的一条增广路。减了后剩余0了。就标记了此路已被访问了。保证了不走重复路。
然后会再次找一条增广路?再次?因为超级源点到1的流量刚才减去1还剩1啊。找到第二条增广路后。超级源点已经无法到达1了,也就是无法到达超级汇点了。
此时求出的费用和正式要求的最小来回费用。
我们把去到回的过程通过最小费用最大流的形式变成了,从超级源点到超级汇点的两条路。(边无交集,虽然超级源点到1这条边重复了,但是费用是0,跟没走一样。)
还要注意,此题,是无向图,故要多建边。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <algorithm> 6 #include <climits> 7 #include <vector> 8 #include <queue> 9 #include <cstdlib> 10 #include <string> 11 #include <set> 12 #include <stack> 13 #define LL long long 14 #define pii pair<int,int> 15 #define INF 0x3f3f3f3f 16 using namespace std; 17 const int maxn = 100100; 18 struct arc{ 19 int u,v,w,f,next; 20 arc(int a = 0,int b = 0,int c = 0,int x = 0,int y = 0){ 21 u = a; 22 v = b; 23 w = c; 24 f = x; 25 next = y; 26 } 27 }; 28 arc e[maxn]; 29 int head[1010],tot,d[1010],n,m,S,T; 30 int p[1010],q[maxn<<2],hd,tail; 31 bool in[1010]; 32 void add(int u,int v,int w,int f){ 33 e[tot] = arc(u,v,w,f,head[u]); 34 head[u] = tot++; 35 e[tot] = arc(v,u,-w,0,head[v]); 36 head[v] = tot++; 37 } 38 bool spfa(){ 39 for(int i = S; i <= T; i++){ 40 d[i] = INF; 41 in[i] = false; 42 p[i] = -1; 43 } 44 hd = tail = 0; 45 in[S] = true; 46 d[S] = 0; 47 q[tail++] = S; 48 while(hd < tail){ 49 int u = q[hd++]; 50 in[u] = false; 51 for(int i = head[u]; ~i; i = e[i].next){ 52 if(e[i].f > 0 && d[e[i].v] > d[u]+e[i].w){ 53 d[e[i].v] = d[u] + e[i].w; 54 p[e[i].v] = i; 55 if(!in[e[i].v]){ 56 in[e[i].v] = true; 57 q[tail++] = e[i].v; 58 } 59 } 60 } 61 } 62 return p[T] > -1; 63 } 64 int solve(){ 65 int ans = 0; 66 while(spfa()){ 67 int maxVal = INF; 68 for(int i = p[T]; ~i; i = p[e[i].u]) 69 maxVal = min(maxVal,e[i].f); 70 for(int i = p[T]; ~i; i = p[e[i].u]){ 71 e[i].f -= maxVal; 72 e[i+1].f += maxVal; 73 ans += maxVal*e[i].w; 74 } 75 } 76 return ans; 77 } 78 int main() { 79 int u,v,w; 80 while(~scanf("%d %d",&n,&m)){ 81 S = tot = 0; 82 T = n+1; 83 memset(head,-1,sizeof(head)); 84 add(S,1,0,2); 85 add(n,T,0,2); 86 for(int i = 0; i < m; i++){ 87 scanf("%d %d %d",&u,&v,&w); 88 add(u,v,w,1); 89 add(v,u,w,1); 90 } 91 printf("%d\n",solve()); 92 } 93 return 0; 94 }
夜空中最亮的星,照亮我前行