【概述】
网络流是一种很神奇的算法,学会了就能打很多暴力(网络流的一些高端操作如线性规划我是不可能会的) 。一般的网络流只限制了边流量的上界,这里介绍一种变形,限制了边流量上下界的,判断是否存在可行流(循环流)。
【算法描述】
我们显然只能借助于最大流算法。下界很讨厌,我们很难在最大流算法中满足对下界的限制。所以我们一开始就让所有边有下界大小的流量。但是,这样某些点的流量显然是不平衡的。为了让这些点达到平衡,我们新建(就是这么简单粗暴 )源点和汇点,让这些点向源点和汇点连边,表示这些点需要源点提供的流量或这些点能向汇点提供的流量。显然,我们接下来需要处理掉新建的点对原图的影响。当且仅当这些新加的边满流时,原图中流量才可以平衡。为了让这些边满流(依然简单粗暴 ),我们从源点开始跑一次最大流即可。因为我们想让源点的出边流量尽量的大,这不就是求最大流吗?如果最后这些新加的边没有满流,那么原图中不存在可行流。
【算法步骤】
- 构造初始流:让所有边有下界的流量,这样可能流量不平衡,不过没关系。
- 将流量不平衡的点向新建的源点或汇点连边,边权表示满足当前情况仍然需要或供大于求的流量。
- 构造附加流:以上界减下界为新边权,从源点出发跑一次最大流。如果源点相连的边都满流,则原问题有解,否则无解。
(其它实现细节见代码,代码虽然不算美观,但是可读)
代码:
#include<bits/stdc++.h>
#define re register
using namespace std;
const int N=1e5+5;
int n,m;
inline int red()
{
int data=0;int w=1; char ch=0;
ch=getchar();
while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
if(ch=='-') w=-1,ch=getchar();
while(ch>='0' && ch<='9') data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
return data*w;
}
struct node{
int u,v,w;
int id;
}e[N<<1|1];
int cnt=1,nxp[N<<1|1],f[N],down[N],up[N],s,t,u[N],v[N];
inline void add(int u,int v,int w,int id)
{
e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;e[cnt].id=0;
nxp[cnt]=f[u];f[u]=cnt;
e[++cnt].u=v;e[cnt].v=u;e[cnt].w=0;e[cnt].id=id;
nxp[cnt]=f[v];f[v]=cnt;
}
int ans[N];
int d[N];
int dis[N],cur[N];
inline bool bfs()
{
queue<int>q;
q.push(s);
memset(dis,-1,sizeof(dis));
dis[s]=0;
while(!q.empty())
{
int u=q.front();q.pop();
for(int re i=f[u];i;i=nxp[i])
{
int v=e[i].v;
if(e[i].w>0&&dis[v]==-1)
{
dis[v]=dis[u]+1;q.push(v);
if(v==t)return 1;
}
}
}
return 0;
}
int dfs(int x,int fff)
{
if(x==t||fff==0)return fff;
int used=0;
for(int &i=cur[x];i;i=nxp[i])
{
int v=e[i].v;
if(e[i].w&&dis[v]==dis[x]+1)
{
int w=dfs(v,min(fff,e[i].w));
if(!w)continue;
used+=w;fff-=w;
e[i].w-=w;e[i^1].w+=w;
if(!fff)break;
}
}
if(!used)dis[x]=-1;
return used;
}
int main()
{
n=red();m=red();s=0;t=n+1;
for(int re i=1;i<=m;i++)
{
u[i]=red();v[i]=red();down[i]=red(),up[i]=red();
d[u[i]]-=down[i];d[v[i]]+=down[i];ans[i]+=down[i];
}
for(int re i=1;i<=n;i++)
{
if(d[i]>0)add(s,i,d[i],0);
if(d[i]<0)add(i,t,-d[i],0);
}
for(int re i=1;i<=m;i++)
if(up[i]>down[i])add(u[i],v[i],up[i]-down[i],i);
while(bfs())
{
for(int re i=0;i<=n+1;i++)cur[i]=f[i];
dfs(s,2e9);
}
for(int re i=f[s];i;i=nxp[i])
if(e[i].w>0)return puts("NO"),0;
for(int re i=1;i<=cnt;i++)
ans[e[i].id]+=e[i].w;
puts("YES");
for(int re i=1;i<=m;i++)
printf("%d\n",ans[i]);
}