题意:
给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质。
并且满足每根pipe一定的流量限制,范围为[Li,Ri].即要满足每时刻流进来的不能超过Ri(最大流问题),同时最小不能低于Li。
题解:
上界用ci表示,下界用bi表示。
下界是必须流满的,那么对于每一条边,去掉下界后,其自由流为ci– bi。
主要思想:每一个点流进来的流=流出去的流
对于每一个点i,令
Mi= sum(i点所有流进来的下界流)– sum(i点所有流出去的下界流)
如果Mi大于0,代表此点必须还要流出去Mi的自由流,那么我们从源点连一条Mi的边到该点。
如果Mi小于0,代表此点必须还要流进来Mi的自由流,那么我们从该点连一条Mi的边到汇点。
如果求S->T的最大流,看是否满流(S的相邻边都流满)。
满流则有解,否则无解。
上下界问题中的实际流量就是:建图后流量+原先下界流量
模板
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
inline int read()
{
int ans,f=1;char ch;
while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';
while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
return ans*f;
}
int n,m,tot,cur[205],head[205],T,S,in[205];
int low[100005];
struct aa
{
int to,pre,flow,cap;
}edge[100005];
void addedge(int u,int v,int d)
{
edge[++tot].to=v;edge[tot].pre=head[u];edge[tot].cap=d;edge[tot].flow=0;head[u]=tot;
edge[++tot].to=u;edge[tot].pre=head[v];edge[tot].cap=0;edge[tot].flow=0;head[v]=tot;
}
void build()
{
for (int i=1;i<=n;i++)
if (in[i]>0) addedge(S,i,in[i]);
else addedge(i,T,-in[i]);
}
int lev[205];
bool bfs()
{
memset(lev,0,sizeof(lev));lev[S]=1;queue<int> q;
q.push(S);
while (!q.empty())
{
int u=q.front();q.pop();
for (int i=head[u];i;i=edge[i].pre)
if (edge[i].cap>edge[i].flow&&lev[edge[i].to]==0)
{
lev[edge[i].to]=lev[u]+1;
if (edge[i].to==T) return true;
q.push(edge[i].to);
}
}
return false;
}
int dfs(int u,int maxflow)
{
if (u==T||maxflow==0) return maxflow;
int ans=0;
for (int &i=cur[u];i;i=edge[i].pre)
if (lev[edge[i].to]==lev[u]+1)
{
int flow=dfs(edge[i].to,min(edge[i].cap-edge[i].flow,maxflow));
maxflow-=flow;
ans+=flow;
edge[i].flow+=flow;
edge[((i-1)^1)+1].flow-=flow;
if (maxflow==0) return ans;
}
return ans;
}
void dinic()
{
int ans=0;
while (bfs())
{
for (int i=1;i<=n+2;i++) cur[i]=head[i];
ans+=dfs(S,inf);
}
}
bool jud()
{
for (int i=head[S];i;i=edge[i].pre)
if (edge[i].cap>edge[i].flow) return false;
return true;
}
int main()
{
int tt=read();
while (tt--)
{
memset(head,0,sizeof(head));tot=0;
memset(in,0,sizeof(in));
n=read(),m=read();
S=n+1,T=n+2;
int u,v,w;
for (int i=1;i<=m;i++)
{
u=read(),v=read(),low[i]=read(),w=read();
in[u]-=low[i],in[v]+=low[i];
addedge(u,v,w-low[i]);
}
build();
dinic();
if (!jud()) printf("NO\n");
else
{
printf("YES\n");
for (int i=1;i<=m;i++)
printf("%d\n",low[i]-edge[i*2].flow);
}
printf("\n");
}
return 0;
}