无向图的最小费用流,建图时可以分别加入两条边(u,v,w,c),(v,u,w,c),即当做两条有向边。 建立一个超级源点和超级汇点,容量为2,其余边容量为1,剩下的就是最小费用流的求解过程了。
POJ 2135 #include<iostream> using namespace std; struct edge { int u,v,next,f,w; }e[40010]; int n,m; int mincost=0; int p[2000]; int num=0; int head[2000]; int s,t; void add(int s,int t,int w,int c) { e[num].f=c; e[num].next=head[s]; head[s]=num; e[num].u=s; e[num].v=t; e[num++].w=w; return ; } void addedge(int s,int t,int w,int c) { add(s,t,w,c); add(t,s,-w,0); return ; } bool spfa() { int i,j; int Q[2000],front(0),tail(0); int d[2000]; bool ok[2000]; memset(ok,0,sizeof(ok)); for(i=0;i<=n+2;i++) { d[i]=INT_MAX; } d[s]=0; ok[s]=1; p[s]=-1; Q[++tail]=s; while(tail!=front) { i=Q[++front]; ok[i]=0; for(j=head[i];j!=-1;j=e[j].next) { if(e[j].f>0&&d[i]+e[j].w<d[e[j].v]) { d[e[j].v]=d[i]+e[j].w; p[e[j].v]=j; if(!ok[e[j].v]) { Q[++tail]=e[j].v; ok[e[j].v]=1; } } } } if(d[t]<INT_MAX) return 1; else return 0; } int solve() { int i; int minflow=INT_MAX; for(i=p[t];i!=-1;i=p[e[i].u]) { if(minflow>e[i].f) minflow=e[i].f; } for(i=p[t];i!=-1;i=p[e[i].u]) { e[i].f-=minflow; e[i^1].f+=minflow; mincost+=e[i].w*minflow; } return 0; } int main() { scanf("%d%d",&n,&m); int i; int a,b,c; memset(head,-1,sizeof(head)); for(i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); addedge(a,b,c,1); addedge(b,a,c,1); } s=0; t=n+1; addedge(s,1,0,2); addedge(n,t,0,2); while(spfa()) { solve(); } printf("%d\n",mincost); system("pause"); return 0; }
|