zoj 2314 有上下界 无源汇 的网络流可行流模板题

题目:http://acm.zju.edu.cn/onlinejudge/submit.do

推荐一篇博客

https://www.cnblogs.com/liu-runda/p/6262832.html

别人已经说的很好了,我能做的就是给一篇有注释的代码 (菜鸡的叹气)

 

#include<bits/stdc++.h>
using namespace std;
const int maxn1=200010,maxn2=300;
//struct edge{
//	int to,val,nxt,i;
//}e[maxn1];  //拆成分开的数组,以  e+在结构体中的名称表示 
int eto[maxn1],eval[maxn1],enxt[maxn1],ei[maxn1]; //将结构体拆成若干数组,速度有明显提升 
int n,m,inds,sup_beg,sup_end,dinic_flag;
//inds:建立边的时候辅助计数   sup_beg: 超级源点(super begging) sup_end: 同理  dinic_flag: 当dinic的值等于这个才表示有附加流 
int head[maxn2],flag[maxn2],deep[maxn2],ans[maxn1],low[maxn1];
// head: 会dinic的都懂  flag:判断该点是什么不守恒  deep:dinic的都懂,深度♂ low:记录每条线下限 
inline int gi(){ //这个是快读,也可以用cin/ scanf代替 
    int f=1,sum=0;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    return f*sum;
}
void add_edge(int fro,int to,int val,int i){
	eto[inds]=to; eval[inds]=val; enxt[inds]=head[fro]; ei[inds]=i; head[fro]=inds++; //加正边 
	eto[inds]=fro; eval[inds]=0; enxt[inds]=head[to]; ei[inds]=i; head[to]=inds++; //反边 
} // ei:记录这条边在输入时的序号,方便最后输出答案的时候知道是哪个顺序 
bool bfs(){
	memset(deep,0,sizeof(deep));
	queue<int> Q;
	Q.push(sup_beg);
	deep[sup_beg]=1;
	while(!Q.empty()){
		int now=Q.front(); Q.pop();
		for(int ind=head[now];ind!=-1;ind=enxt[ind]){
			int to=eto[ind]; 
			if(!deep[to]&&eval[ind]){
				deep[to]=deep[now]+1;
				Q.push(to);
			}
		}
	}
	return deep[sup_end];
}
int dfs(int num,int flow){
	if(num==sup_end) return flow;
	int max_flow=0;
	for(int ind=head[num];ind!=-1;ind=enxt[ind]){
		int to=eto[ind];
		if(deep[to]==deep[num]+1&&eval[ind]){
			int sto_flow=dfs(to,min(flow,eval[ind]));
			flow-=sto_flow; //这句一开始我忘记加了 
			max_flow+=sto_flow;
			eval[ind]-=sto_flow;
			eval[ind^1]+=sto_flow;
			if(flow==0) break;
		}
	}
	if(max_flow==0) deep[num]=0;
	return max_flow;
}
int dinic(){ //dinic嘛。不多解释了,可以看我另外一篇博客 https://blog.csdn.net/weixin_43191865/article/details/88604415 
	int sum=0;
	while(bfs()){
		sum+=dfs(sup_beg,0x3f3f3f3f);
	}
	return sum;
}
int main(){
	int cnt=gi();  //快读快读 
	while(cnt--){
		n=gi();
		m=gi();
		memset(eto,0,sizeof(eto)); memset(eval,0,sizeof(eval)); memset(ei,0,sizeof(ei));
		memset(enxt,0,sizeof(enxt));
		memset(head,-1,sizeof(head));
		memset(flag,0,sizeof(flag));
		inds=0; sup_beg=0; sup_end=n+1;
		for(int i=1;i<=m;i++){
			int fro=gi(),to=gi(),dow=gi(),up=gi(); 
			add_edge(fro,to,up-dow,i);
			low[i]=dow;  
			flag[fro]-=dow; flag[to]+=dow;  
		}
		dinic_flag=0;
		for(int i=1;i<=n;i++){
			if(flag[i]>0){
				add_edge(sup_beg,i,flag[i],0);
				dinic_flag+=flag[i]; //因为边是双向的,只需要记录一边 
			}
			if(flag[i]<0){
				add_edge(i,sup_end,-flag[i],0);
			}
		}
		if(dinic()==dinic_flag){
			puts("YES");
			memset(ans,0,sizeof(ans));
			for(int i=1;i<=n;i++){
				for(int ind=head[i];ind!=-1;ind=enxt[ind]){
					int to=eto[ind];
					if(to==sup_end||ind%2==0) continue; // 只要反边 
					ans[ei[ind]]=eval[ind]+low[ei[ind]];
				}
			}
			for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
		}
		else puts("NO");
	}
	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值