标签:poj2135 farm tour 最大流 最小费用流 acm
Description
Input
Output
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; }
标签:poj2135 farm tour 最大流 最小费用流 acm
原文地址:http://blog.csdn.net/maxichu/article/details/45362483