解题报告 之 POJ2135 Farm Tour
Description
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.
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.
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
题目大意:给你一个无向图,有n个节点编号1~n,m条边。且起点为1,终点为n。给出每条边的长度,并要求每条边只能走一次,问你从起点走到终点再从终点走回起点的最短路是多少?
分析:首先直观的感觉到,如果可以重复走那么直接上SPFA即可。但是这道题要求每天边只能走一次,那么最短路算法就无效了。所以我们该怎么办呢?建议你先参考另一篇博文,这是边不重复最短路模型,这道题似乎是该模型的最小费用流升级版。
ZOJ 2760 How Many Shortest Path
http://blog.csdn.net/maxichu/article/details/45151399
那么至此我已经假设你明白边不重复最短路了。通过最大流我们可以找到有几天边不重复的最短路,但是此题并不要求是两条最短路而是总长度最短即可。所以我们必须引入最小费用流来解题了。最小费用流的理论建议看《挑战》,但是感觉《挑战》的代码实现比较凌乱不是很适合我这种小白,于是我看懂了之后自创了一个模板(赞起来。囧)。。那么此题的其实就是最基本的一个最小费用流了。
首先超级源点连接节点1,负载为2,费用为0。然后根据输入建图即可,节点n与超级汇点连接,负载为2,费用为0。然后跑一条最大流为2的最小费用流即是答案。我的模板中采用了《挑战》的h标号法,但此题并不存在负权边,我只是为了存个模板。。。
上代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<deque> using namespace std; const int MAXN = 90010; const int MAXM = 910000; const int INF = 0x3f3f3f3f; struct Edge { int from, to, cap, next, cost; }; Edge edge[MAXM]; int prevv[MAXN]; int preve[MAXN]; int dist[MAXN]; int head[MAXN]; int h[MAXN]; //标号数组 int src, des, cnt; void addedge( int from, int to, int cap, int cost ) { edge[cnt].from = from; edge[cnt].to = to; edge[cnt].cap = cap; edge[cnt].cost = cost; edge[cnt].next = head[from]; head[from] = cnt++; swap( from, to ); edge[cnt].from = from; edge[cnt].to = to; edge[cnt].cap = 0; edge[cnt].cost = -cost; edge[cnt].next = head[from]; head[from] = cnt++; } int SPFA( ) { deque<int> dq; bool inqueue[MAXN]; memset( dist, INF, sizeof dist ); memset( inqueue, 0, sizeof inqueue ); dq.push_back( src ); inqueue[src] = 1; dist[src] = 0; while(!dq.empty()) { int u = dq.front(); dq.pop_front(); inqueue[u] = 0; for(int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].to; if(edge[i].cap > 0 && dist[u] + edge[i].cost +h[u]-h[v]< dist[v]) { dist[v] = dist[u] + edge[i].cost + h[u] - h[v]; prevv[v] = u; preve[v] = i; if(!inqueue[v]) { if(!dq.empty() && dist[v] <= dist[dq.front()]) { dq.push_front( v ); } else dq.push_back( v ); } } } } return 0; } int min_cost_flow(int f,int n) { memset( h, 0, sizeof h ); int cost = 0; while(f > 0) { SPFA(); if(dist[des] == INF) { return -1; } for(int u = 1; u <= n; u++) h[u] += dist[u]; h[des] += dist[des]; int d = f; for(int i = des; i != src; i = prevv[i]) { d = min( d, edge[preve[i]].cap ); }//此处循环比较鸡肋因为负载都为1。 f -= d; cost += d*h[des]; for(int i = des; i != src; i = prevv[i]) { edge[preve[i]].cap -= d; edge[preve[i] ^ 1].cap += d; } } return cost; } int main( ) { int n, m; src = 0; des = 90005; while(cin >> n >> m) { memset( head, -1, sizeof head ); cnt = 0; int a, b, c; for(int i = 1; i <= m; i++) { cin >> a >> b >> c; addedge( a, b, 1, c ); addedge( b, a, 1, c ); } addedge( src, 1, 2, 0 ); addedge( n, des, 2, 0 ); cout << min_cost_flow(2,n) << endl; } return 0; }
昨天熬夜搞完WebServer,看来今天要复习一下计网和嵌入式和通信原理了。靠,,我绝对没有暴露我的专业背景。你们绝对猜不到我是啥专业的!