把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

LOJ #115. 无源汇有上下界可行流

题面传送门
这个东西看上去其实很难做。
有一个naive的想法就是把每条边的权值重新定为\(upp-low\),然后跑最大流。
但是有一部分流量会飞掉。有一些点入流不等于出流。
这时候我们建一个超级源与超级汇。
\(cnt_u=\sum\limits_{(v,u)\in E}{low_{(v,u)}}-\sum\limits_{(u,v)\in E}{low_{(u,v)}}\)
如果\(cnt_u>0\),那么从源点向\(u\)连一条容量为\(cnt_u\)的边,因为在现在的流量网络中\(u\)是少了这么多出流的所以要补上。
反之则向汇点连\(-cnt_u\)的边即可。
判断有没有解就看源点是否满流即可。
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);
}
posted @ 2021-05-29 16:00  275307894a  阅读(42)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end