LOJ #116. 有源汇有上下界最大流
题面传送门
我们已经知道无源汇怎么办了,现在考虑有源汇。
可以发现除了源点和汇点都是满足流量守恒的。所以我们只要让源点和汇点流量守恒即可。
所以只要给汇点流向源点无限容量边即可。
但是这个只是一个可行流。不是最大流。
我们要想办法将其变成最大流。因为虚拟源和虚拟汇都被我流满了,所以改成在起初的源点和汇点流即可求出答案。
code:
#include <vector>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<bitset>
#include<set>
#include<map>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define l(x) x<<1
#define r(x) x<<1|1
#define re register
#define ll long long
#define db long double
#define N 200
#define eps (1e-14)
#define mod 998244353
using namespace std;
int n,m,x,y,z,d[N+5],id[N*N+5],w[N+5],nows[N+5],st,t,ans[N*N+5],tot,now;
struct yyy{int to,w,z;}tmp;
struct ljb{
int head,h[N+5];yyy f[N*N+5<<2];
I void add(int x,int y,int z){f[head]=(yyy){y,z,h[x]};h[x]=head++;}
}s;queue<int> q;
I void get(int x,int y,int z){s.add(x,y,z);s.add(y,x,0);}
I int bfs(){
memset(d,0x3f,sizeof(d));memset(nows,-1,sizeof(nows));while(!q.empty()) q.pop();q.push(st);d[st]=0;nows[st]=s.h[st];
re int i;while(!q.empty()){
now=q.front();q.pop();
for(i=s.h[now];~i;i=tmp.z){
tmp=s.f[i];if(!tmp.w||d[tmp.to]<1e9) continue;d[tmp.to]=d[now]+1;
nows[tmp.to]=s.h[tmp.to];q.push(tmp.to);if(tmp.to==t) return 1;
}
}
return 0;
}
I int dfs(int x,int sum){
if(x==t) return sum;yyy tmp;re int i,pus=0,k;
for(int i=nows[x];~i;i=tmp.z){
tmp=s.f[i];nows[x]=i;if(d[tmp.to]==d[x]+1&&tmp.w){
k=dfs(tmp.to,min(tmp.w,sum));if(!k) d[tmp.to]=1e9;
s.f[i].w-=k;s.f[i^1].w+=k;sum-=k;pus+=k;
}
if(!sum) break;
}
return pus;
}
int main(){
freopen("1.in","r",stdin);
re int i;scanf("%d%d",&n,&m);memset(s.h,-1,sizeof(s.h));for(i=1;i<=m;i++) scanf("%d%d%d%d",&x,&y,&ans[i],&z),get(x,y,z-ans[i]),id[i]=s.head-1,w[y]+=ans[i],w[x]-=ans[i];
st=0;t=n+1;for(i=1;i<=n;i++) w[i]>0?(tot+=w[i],get(st,i,w[i])):get(i,t,-w[i]);while(bfs()) tot-=dfs(st,1e9);
if(tot){printf("NO\n");return 0;}printf("YES\n");for(i=1;i<=m;i++)printf("%d\n",ans[i]+s.f[id[i]].w);
}