题意:在一个网络中有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;
}