题意:在一个网络中有M条管道,有一些管道必须满流.这个网络中有标号为1 的源点和标号为N的汇点。求此网络流中的最小流。
做法:一般的上下界网络流,可以用来测试模板。
#include<stdio.h> #include<string.h> #define LMT 200 #define eps 2e9 typedef struct { int u,v; }line; line e[LMT*LMT]; int mat[LMT][LMT],fmat[LMT][LMT],lim[LMT][LMT],lev[LMT],q[LMT]; int n,m,sum; int bfs(int s,int t) { int i,j,tail,head; memset(lev,0,sizeof(lev)); lev[s]=1;head=tail=0; q[tail++]=s; while(head<tail) { i=q[head++]; for(j=0;j<=n+1;j++) if(fmat[i][j]>0&&0==lev[j]) { lev[j]=lev[i]+1; q[tail++]=j; } } return lev[t]!=0; } int dfs(int s,int t) { int i,j,top=0,ret=0; q[top++]=s; while(top>0) { i=q[top-1]; if(i==t) { int min,back; min=eps; for(i=1;i<top;i++) { if(min>fmat[q[i-1]][q[i]]) { min=fmat[q[i-1]][q[i]]; back=i; } } ret+=min; for(i=1;i<top;i++) { fmat[q[i-1]][q[i]]-=min; fmat[q[i]][q[i-1]]+=min; } top=back; } else { for(j=0;j<=n+1;j++) if(fmat[i][j]>0&&lev[j]==lev[i]+1) { q[top++]=j; break; } if(j>n+1) { lev[i]=0; top--; } } } return ret; } int dinic(int s,int t) { int ret=0; while(bfs(s,t)) ret+=dfs(s,t); return ret; } int test(int s,int t,int mid) { int tn; sum=0; mat[n][1]=mid; memset(fmat,0,sizeof(fmat)); int i,j; for(i=1;i<=n;i++) { tn=0; for(j=1;j<=n;j++) { tn+=lim[j][i]-lim[i][j]; fmat[i][j]=mat[i][j]-lim[i][j]; } if(tn>0) { fmat[s][i]=tn; sum+=tn; } else fmat[i][t]=-tn; } return dinic(s,t)>=sum; } int main() { int l,r,i,j,c,d,mid,x,ans; scanf("%d%d",&n,&m); memset(mat,0,sizeof(mat)); memset(lim,0,sizeof(lim)); r=0;l=0;//这里的L必须为0,否则会出现错误,不知为何显示的PE for(x=0;x<m;x++) { scanf("%d%d%d%d",&i,&j,&c,&d); r+=c; mat[i][j]=c; if(d) lim[i][j]=c; e[x].u=i; e[x].v=j; } ans=-1; while(l<=r) { mid=(l+r)>>1; if(test(0,n+1,mid)) { r=mid-1; ans=mid; } else l=mid+1; } if(ans==-1) { puts("Impossible"); return 0; } else { test(0,n+1,ans); printf("%d\n",ans); for(i=0;i<m;i++) printf("%d%c",mat[e[i].u][e[i].v]-fmat[e[i].u][e[i].v],i==m-1?'\n':' '); } return 0; }