/*
我也没有读题 刚学就直接搜的这类题 找了个简单的练习
大致上好像是这么个意思 给你一个图 边有上下界
求无源汇最大流 没有输出NO 有则输出 YES 并输出 各边的流量
*/
#include<iostream>
#include<string.h>
using namespace std;
const int N=205;
struct node
{
int u,v;
}e[N*N];
int l[N][N],u[N][N],g[N][N],d[N],num[N],n,m,sink,src;
int min(int a,int b){return a<b?a:b;}
int sap(int u,int f)
{
if(u==sink)
return f;
int v,mind=n+1,last=f,cost;
for(v=0;v<=n+1;++v)
{
if(g[u][v]>0)//有流量
{
if(d[u]==d[v]+1)//有允许边
{
cost=sap(v,min(last,g[u][v]));
g[u][v]-=cost;//修改图
g[v][u]+=cost;
last-=cost;//修改剩余流量
if(d[src]>=n+2)//结束标志
return f-last;
if(last==0)//使用完就退出
break;
}
if(d[v]<mind)//下面更新距离的时候用 求其能连接到的最小距离 这个判断和上边的那个判断并列 因为他们是互斥的,只有当找不到允许边的时候才用得着mind
mind=d[v];
}
}
if(last==f)//流量没有使用 即 没有允许边
{
--num[d[u]];
if(num[d[u]]==0)//若出现断层
{
d[src]=n+2;
}
d[u]=mind+1;
++num[d[u]];
}
return f-last;
}
int main()
{
int t,i,j,a,b,c,h;
cin>>t;
while(t--)
{
memset(g,sizeof(g));
memset(l,sizeof(l));//曾经忘了初始化这俩 老是错
memset(u,sizeof(u));//
cin>>n>>m;
sink=n+1;
src=0;
for(i=1;i<=m;++i)
{
cin>>a>>b>>c>>h;
e[i].u=a;//记录边 以便 存在答案是输出用
e[i].v=b;
l[a][b]=c;
u[a][b]=h;
}
b=0;
for(i=1;i<=n;++i)
{
a=0;
for(j=1;j<=n;++j)
{
a+=l[j][i]-l[i][j];//统计 输入流比输出流多多少
g[i][j]=u[i][j]-l[i][j];
}
if(a>0)
b+=g[0][i]=a;
else g[i][n+1]=-a;
}
c=0;
memset(d,sizeof(d));
memset(num,sizeof(num));
for(num[0]=n+2;d[0]<n+2;)
c+=sap(0,0x7fffffff);
if(c<b)
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
for(i=1;i<=m;++i)
cout<<(u[e[i].u][e[i].v]-g[e[i].u][e[i].v])<<endl;
}
}
return 0;
}
原文链接:/react/308285.html