无源汇上下界可行流
可行流即对于一张无源点与汇点的流量网络(G)
询问是否存在一种流量方案,使得每条边的流量在对应的上下界内,且每个点流量平衡
解法
既然对于流量网络(G)内每一条边的流量都进行了限制,使其必须处于([L_i,R_i])之内
那么就假设每条边一开始就存在着要求的最小流量(L_i)
这条边此时的容量便变成了(R_i-L_i),初始流量为(0),以此初步建立流量网络
这样处理便解决了上下界的限制
但同时也导致每个点的流量不一定平衡,即流入量≠流出量
所以接下来要对点进行平衡处理,使得每条边与原图中对应的边相加后,全图流量平衡
构建虚拟源点(S)与虚拟汇点(T),使得能够虚拟提供流量
由于上面我们处理时使得每条边都固定拥有了流量(L_i)
那么对于这条边连接的两个点(u_i,v_i)
即(u_i)的流出量(out[u_i]+=L_i),(v_i)的流入量(in[v_i]+=L_i)
处理完所有边后,得到每个点的总流入量与总流出量
可得,如果对于点(i)
(in[i]>=out[i]):该点流入量较流出量大,说明点(i)需要多向外输出(in[i]-out[i])的流量,那么这些流量就从虚拟源点(S)取,故建立(S)至(i)的流量为(in[i]-out[i])的一条边
(in[i]<out[i]):该点流出量较流入量大,说明外面需要多向点(i)输入(out[i]-in[i])的流量,换言之可以将该点多余的流量流向虚拟汇点(T),故建立(i)至(T)的流量为(out[i]-in[i])的一条边
可行流求解
如上建立流量网络
可知,对于与源点/汇点连接的边的容量和代表着全图的流量总和
令所有(in[i]>=out[i])情况下的(in[i]-out[i])总和为(sum)(或所有(in[i]<out[i])情况下的(out[i]-in[i])总和)
对于这个流量网络,只有当最大流量流满(sum)时,才能做到全图的流量平衡
所以直接跑Dinic,判断最大流是否等于(sum)即可
例题
模板题,多组数据,给定点数与边数,给出每条边连向即上下界,问一种使得流量平衡的可行解
最后取出跑Dinic后每条边对应的反向边流量作为该边的流量,加上初始的流量下界作为该边最终流量即可
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=200,maxm=40000;
struct edge{
int u,v,cap,flow;
edge(){}
edge(int u,int v,int cap,int flow):u(u),v(v),cap(cap),flow(flow){}
}eg[maxm<<1];
int tot,s,t,dis[maxn<<1],cur[maxn<<1];
vector<int> tab[maxn<<1];
void init(int n,int s_,int t_){
while(n)tab[n--].clear();
tot=0,s=s_,t=t_;
}
void addedge(int u,int v,int cap){
tab[u].push_back(tot);
eg[tot++]=edge(u,v,cap,0);
tab[v].push_back(tot);
eg[tot++]=edge(v,u,0,0);
}
int bfs(){
queue<int> q;
q.push(s);
memset(dis,INF,sizeof dis);
dis[s]=0;
while(!q.empty()){
int h=q.front(),i;
q.pop();
for(i=0;i<tab[h].size();i++){
edge &e=eg[tab[h][i]];
if(e.cap>e.flow&&dis[e.v]==INF){
dis[e.v]=dis[h]+1;
q.push(e.v);
}
}
}
return dis[t]<INF;
}
int dfs(int x,int maxflow){
if(x==t|maxflow==0)
return maxflow;
int flow=0,i,f;
for(i=cur[x];i<tab[x].size();i++){
cur[x]=i;
edge &e=eg[tab[x][i]];
if(dis[e.v]==dis[x]+1&&(f=dfs(e.v,min(maxflow,e.cap-e.flow)))>0){
e.flow+=f;
eg[tab[x][i]^1].flow-=f;
flow+=f;
maxflow-=f;
if(maxflow==0)
break;
}
}
return flow;
}
int dinic(){
int flow=0;
while(bfs()){
memset(cur,0,sizeof(cur));
flow+=dfs(s,INF);
}
return flow;
}
struct node
{
int u,v,l,r;
}E[maxm<<1];
int in[maxn],out[maxn];
void solve()
{
int n,m,u,v,sum=0;
scanf("%d%d",&n,&m);
init(n+2,n+1,n+2);
for(int i=1;i<=n;i++)
in[i]=out[i]=0;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%d",&E[i].u,&E[i].v,&E[i].l,&E[i].r);
in[E[i].v]+=E[i].l;
out[E[i].u]+=E[i].l;
addedge(E[i].u,E[i].v,E[i].r-E[i].l); //限制流量为r-l
}
for(int i=1;i<=n;i++)
{
if(in[i]>=out[i])
addedge(s,i,in[i]-out[i]),sum+=in[i]-out[i];
else
addedge(i,t,out[i]-in[i]);
}
if(dinic()<sum)
{
puts("NO");
return;
}
puts("YES");
for(int i=1;i<2*m;i+=2)
printf("%d
",E[i/2+1].l+eg[i^1].flow); //从跑出的残量网络中取反向边的flow为当前可行流量,加上原先的下界作为流量
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
solve();
return 0;
}