Poj2135 Farm Tour (最小费用流)

题目链接:http://poj.org/problem?id=2135

 

题意:给出一个无向有权图,问从出发点到终点然后返回的每条边最多经过一次的最短路径.

 

此题可以转化为网络流来解,首先每条边只能经过一次,则给每条边设一个容量1,在扩增的时候,每条边的流量不会超过1,然后就是最小费用流的求解了,从原点出发至终点,然后从终点返回,由于是无向图,则可以看作从原点出发两次不经过相同的路径,分别到达终点的最小费用.

 

最小费用流的求法:寻找增广路径的时候用SPFA来实现,这样可以解决带负边权的路径问题的最短路,然后就是对选出的最短路进行增广了.

 

#include<stdio.h> #include<string.h> #include<queue> using namespace std; #define N 1028 #define M 10028 #define INF 0x7fffffff typedef struct{ int u,v,c,f; int next; }Edge; Edge edg[4*M]; int head[N]; int path[N]; int dis[N]; bool inq[N]; int n,m,e,ans; void AddEdge(int u,int v,int c) { edg[e].u=u; edg[e].v=v;edg[e].c=c;edg[e].f=1; edg[e].next=head[u];head[u]=e++; edg[e].u=v; edg[e].v=u;edg[e].c=-c;edg[e].f=0; edg[e].next=head[v];head[v]=e++; } void SPFA() { int i,u,tmp; queue<int>q; for(i=0;i<=n;i++){ inq[i]=false; dis[i]=INF; path[i]=-1; }inq[1]=true; dis[1]=0; q.push(1); while(!q.empty()){ u=q.front();q.pop(); inq[u]=false; for(tmp=head[u];tmp!=-1;tmp=edg[tmp].next){ if(dis[edg[tmp].v]-dis[u]>edg[tmp].c&&edg[tmp].f){ dis[edg[tmp].v]=dis[u]+edg[tmp].c; path[edg[tmp].v]=tmp; if(!inq[edg[tmp].v]){ inq[edg[tmp].v]=true; q.push(edg[tmp].v); } } } } } void Work() { int tmp,i; for(i=ans=0;i<2;i++){ SPFA(); ans+=dis[n]; for(tmp=path[n];tmp!=-1;tmp=path[edg[tmp].u]){ edg[tmp].f-=1; edg[tmp^1].f+=1; } } } int main() { int u,v,c; scanf("%d%d",&n,&m); e=0; memset(head,-1,sizeof(head)); while(m--){ scanf("%d%d%d",&u,&v,&c); AddEdge(u,v,c); AddEdge(v,u,c); } Work(); printf("%d/n",ans); return 0; }  

你可能感兴趣的:(c,网络,struct,Path)