题目:
无源汇可行流例题
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1314
题解:
证明什么的就算了,下面给出一种建图方式
1.建虚拟的S和T
2.每一条原图的边(u,v),设最大容量是Max,最小是Min,建一条容量为Max-Min的边(u,v),同时令ind[v]和oud[u]+=Min,表示实际应该多流入(出)的流量
3.对于每个点u,如果ind[u]>oud[u],为了满足流量平衡条件,所以让S和u连一条容量为ind[u]-oud[u]的边
如果ind[u]<oud[u],同理,我们让u和T连一条容量为oud[u]-ind[u]的边
4.跑最大流
5.如果S的出边都流满就说明有解,反之没有
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 205
#define M 100005
#define INF 0x3f3f3f3f
using namespace std;
int TT,n,m,S,T,ans,sum,dis[N],cur[N],u[M],v[M],mi[M],ma[M],ind[N],oud[N],ecnt=,head[N];
queue<int> q;
struct adj{int nxt,v,w;}e[M];
int read()
{
int ret=,neg=;char j=getchar();
for (;j>'' || j<'';j=getchar())
if (j=='-') neg=-;
for (;j>='' && j<='';j=getchar())
ret=ret*+j-'';
return ret*neg;
}
void add(int u,int v,int w)
{
e[++ecnt].v=v;e[ecnt].w=w;e[ecnt].nxt=head[u];head[u]=ecnt;
e[++ecnt].v=u;e[ecnt].w=;e[ecnt].nxt=head[v];head[v]=ecnt;
}
void init()
{
ans=sum=;ecnt=;
for (int i=;i<=T;i++)
ind[i]=oud[i]=head[i]=;
}
bool Bfs()
{
while (!q.empty()) q.pop();
for (int i=;i<=T;i++)
cur[i]=head[i],dis[i]=-;
dis[S]=;q.push(S);
while (!q.empty())
{
int u=q.front();q.pop();
for (int i=head[u],v;i;i=e[i].nxt)
if (e[i].w && dis[v=e[i].v]==-)
{
dis[v]=dis[u]+,q.push(v);
if (v==T) return ;
}
}
return ;
}
int Dfs(int u,int flow)
{
if (u==T) return flow;
int ret=,delta;
for (int &i=cur[u],v;i;i=e[i].nxt)
if (e[i].w && dis[v=e[i].v]==dis[u]+)
{
delta=Dfs(v,min(e[i].w,flow-ret));
if (delta)
{
e[i].w-=delta;
e[i^].w+=delta;
ret+=delta;
if (ret==flow) break;
}
}
return ret;
}
int main()
{
TT=read();
while (TT--)
{
n=read();m=read();S=n+;T=n+;
init();
for (int i=;i<=m;i++)
{
u[i]=read();v[i]=read();mi[i]=read();ma[i]=read();
add(u[i],v[i],ma[i]-mi[i]);
oud[u[i]]+=mi[i],ind[v[i]]+=mi[i];
}
for (int i=;i<=n;i++)
if (ind[i]>oud[i])
add(S,i,ind[i]-oud[i]),sum+=ind[i]-oud[i];
else
add(i,T,oud[i]-ind[i]);
while (Bfs())
ans+=Dfs(S,INF);
if (ans<sum)
puts("NO");
else
{
puts("YES");
for (int i=;i<=m;i++)
printf("%d\n",mi[i]+e[i*+].w);
}
}
return ;
}