链接:http://poj.org/problem?id=2135
做题思路出处:http://www.cnblogs.com/rainydays/archive/2012/07/05/2577386.html
题意:给定一个无向图,要从1点到n点再返回1点,每条边最多走一次,问最短需要走多远。
分析:最小费用最大流,把题意看成是要找两条无交集的从1到n的路线,使距离和最小。图中的点和边就是网络流图中的点和边。设置一个源,接到1点,设置一个汇,从n点接到汇。为保证无交集,我们把每条边的流量设置为1,而源发出的流量和汇接收的流量均为2。每条边的费用就是该边在原图中的权值。
注意:有重边,所以要用邻接表。因为是无向图,所以要在加边时,原图中的一条边要变成网络流图中的两条边(如果把反向负权费用边也算上就总共4条边)。
由于最短路算法是最小费用最大流算法的子算法,所以有些最短路的题可能要用到最小费用最大流。
我觉得构图的两个地方很关键,一个就是对无向图的诠释。还有一个就是在容量的设定上:源点和汇点的连边都设置为2,其它都为1。虽然分析指出了这样做的原因。但可能自己来想还是有点捉急。
这样求得两条无交集的路线的最大流看来一定是2,题目中也说明必定会有来回的路,且不走相同的路。具体整个过程怎么实现的,还是有点模模糊糊。就觉得大概是这样。。。。好吧。代码就没什么好说的了,套一下MCMF的模板就可以了。关键是构图啊,构图!
#include<cstdio>
#include<cstring>
#include<queue>
#define MAXE 40005
#define MAXN 1100
#define INF 0x7fffffff
#define MIN(a,b) a>b?b:a
using namespace std;
int n,m;
int st,ed,cnt;
int mincost;
int head[MAXN],dist[MAXN],vist[MAXN],pre[MAXN],pos[MAXN];
struct Edge
{
int to;
int cap;
int cost;
int next;
}edge[MAXE];
void add(int u,int v,int cap,int cost)
{
edge[cnt].to=v;
edge[cnt].cap=cap;
edge[cnt].cost=cost;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].to=u;
edge[cnt].cap=0;
edge[cnt].cost=-cost;
edge[cnt].next=head[v];
head[v]=cnt++;
}
void MCMF(int st,int ed)
{
int i,u,v;
int aug;
mincost=0;
for(;;)
{
memset(vist,0,sizeof(vist));
memset(pre,-1,sizeof(pre));
for(i=0;i<=ed;i++)
dist[i]=INF;
dist[st]=0;
pre[st]=st;
vist[st]=1;
queue<int> q;
q.push(st);
while(!q.empty())
{
u=q.front();
q.pop();
vist[u]=0;
for(i=head[u];i!=-1;i=edge[i].next)
{
v=edge[i].to;
if(edge[i].cap>0&&dist[v]>dist[u]+edge[i].cost)
{
dist[v]=dist[u]+edge[i].cost;
pre[v]=u;
pos[v]=i;
if(!vist[v])
{
vist[v]=1;
q.push(v);
}
}
}
}
if(pre[ed]==-1)
break;
aug=INF;
for(u=ed;u!=st;u=pre[u])
aug=MIN(aug,edge[pos[u]].cap);
mincost+=dist[ed]*aug;
for(u=ed;u!=st;u=pre[u])
{
edge[pos[u]].cap-=aug;
edge[pos[u]^1].cap+=aug;
}
}
return ;
}
int main()
{
int i,a,b,c;
while(scanf("%d%d",&n,&m)!=EOF)
{
st=0;
ed=n+1;
cnt=0;
memset(head,-1,sizeof(head));
for(i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,1,c);
add(b,a,1,c);
}
add(st,1,2,0); //源点和汇点的连边容量设置为2
add(n,ed,2,0);
MCMF(st,ed);
printf("%d\n",mincost);
}
return 0;
}