题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2314
输入:第一行包含数字N,节点的个数和M,管道的数量。接下来的M行包含4个整数,i,j,lij,cij。没有管道连接到自己。如果有一个管道从i连到j,那么就没有管道从j连到i
输出:如果有办法启动反应堆,第一行输出YES,否则,第一行输出NO。第一种情况下,将输出M个整数,第K个是第K个管道的液体量。
思路:无源汇有上下界网络的可行流模板题:https://blog.csdn.net/axuan_k/article/details/47282421。
流量可以通过反向边的流量得到。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=2e5+10;
struct E
{
int v; //每一条边指向的点
int w; //每一条边的残量
int next;//指向对应点的前一条边
}e[maxm*2];
int s, t;
int cut;
int head[maxm];
int d[maxn];
int inf=(1<<31)-1;
int cur[maxn];
int id[maxm*2];
int dis[maxn];
int low[maxm];
int n, m;
void init()
{
cut=-1;
memset(dis, 0, sizeof(dis));
memset(head, -1, sizeof(head));
}
void add(int u, int v, int w, int i)
{
cut++;
e[cut]=E{v, w, head[u]};
head[u]=cut++;
e[cut]=E{u, 0, head[v]};
id[i]=head[v]=cut;
}
int bfs()
{
queue<int> q;
while(!q.empty())
{
q.pop();
}
memset(d, 0, sizeof(d));
d[s]=1;
q.push(s);
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].v, w=e[i].w;
if(w>0&&d[v]==0)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
if(d[t]==0)
{
return 0;
}
return 1;
}
int dfs(int u, int dis)
{
if(u==t)
{
return dis;
}
for(int &i=cur[u];i!=-1;i=e[i].next)
{
int v=e[i].v, w=e[i].w;
if((d[v]==d[u]+1)&&w!=0)
{
int di=dfs(v, min(dis, w));
if(di>0)
{
e[i].w-=di;
e[i^1].w+=di;
return di;
}
}
}
return 0;
}
int Dinic()
{
int ans=0;
while (bfs())
{
for(int i=s;i<=t+1;i++)
{
cur[i]=head[i];
}
while (int d=dfs(s,inf))
{
ans+=d;
}
}
return ans;
}
int main()
{
int T;
cin>>T;
while(T--)
{
scanf("%d%d",&n,&m);
init();
for(int i=1;i<=m;i++)
{
int u, v, l, p;
scanf("%d%d%d%d",&u,&v,&low[i],&p);
add(u, v, p-low[i], i);
dis[u]-=low[i];
dis[v]+=low[i];
}
int sum=0;
for(int i=1;i<=n;i++)
{
if(dis[i]>0)
{
add(0, i, dis[i], 0);
sum+=dis[i];
}
else
{
add(i, n+1, -dis[i], 0);
}
}
s=0, t=n+1;
if(Dinic()==sum)
{
printf("YES\n");
for(int i=1;i<=m;i++)
{
printf("%d\n",low[i]+e[id[i]].w);
}
}
else
{
cout<<"NO"<<endl;
}
cout<<endl;
}
return 0;
}