标签: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