HDU 4940 无源无汇上下界最大流

56 篇文章 0 订阅
9 篇文章 0 订阅


题意具体解释


题目意思其实是对于每个点来说,从这个点流出的流量,能通过其他边流动回来,这就是无源无汇有上下界的最大流了。

对于每条有向边来说。  它的下界是  B,  上界是B+D。

参考 周源 《一种简易的方法求解流量有上下界的网络中网络流问题》  的构图方法




对于原图,更改容量,C'(u, v) = C(u, v) - B(u, v) , 同时  C(u,v) = 就是题目给出的B+D,  B(u,v) = 题目给出的 B

同时,增设源点S,汇点T

对于每个点,如果M( i ) > 0,则建边<S, i, M( i )>,如果M(i) < 0,则建边< i, T, -M( i )>

对新图求一次S-->T最大流,如果与S, T相连的边全部满流,则原图中存在一个可行流,保证每个点的流量守恒。


//tpl
//ipqhjjybj_tpl.h
//header.h
#include <cstdio>
#include <cstdlib>
#include <map>
#include <set>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <sstream>
#include <math.h>

#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pLL pair<long long ,long long>
#define pb(x) push_back(x)
#define rep(i,j,k) for(int i = j; i < k;i++)

#define MAX(x,a)  x=((x)<(a))?(a):(x);
#define MIN(x,a)  x=((x)>(a))?(a):(x);

using namespace std;

const int N = 500;
int n,m,tot;
int s,t;
int sum;
struct node{
	int u,v,w,next;
	node(){}
	node(int _u,int _v,int _w,int _next){
		u=_u,v=_v,w=_w,next=_next;
	}
}edge[N*N];
int head[N],cur[N],dis[N];
int pre[N],gap[N],aug[N];
const int oo=0x3f3f3f;
void addEdge(int u,int v,int w){
	edge[tot]=node(u,v,w,head[u]);
	head[u]=tot++;
	edge[tot]=node(v,u,0,head[v]);
	head[v]=tot++;
}

int SAP(int s,int e,int n){
	int max_flow=0,v,u=s;
	int id,mindis;
	aug[s]=oo;
	pre[s]=-1;
	memset(dis,0,sizeof(dis));
	memset(gap,0,sizeof(gap));
	gap[0]=n;

	for(int i=0;i <= n;i++)
		cur[i]=head[i];

	while(dis[s]<n){
		if(u==e){
			max_flow += aug[e];
			for(v=pre[e]; v!=-1; v=pre[v]){
				int ed=cur[v];
				edge[ed].w -= aug[e];
				edge[ed^1].w += aug[e];
				aug[v]-=aug[e];
				if(edge[ed].w==0) u=v;
			}
		}
		bool flag=false;
		for(id=cur[u]; id!=-1;id=edge[id].next){
			v=edge[id].v;
			if(edge[id].w > 0 && dis[u]==dis[v]+1){
				flag=true;
				pre[v]=u;
				cur[u]=id;
				aug[v]=min(aug[u],edge[id].w);
				u=v;
				break;
			}
		}
		if(flag==false){
			if(--gap[dis[u]] == 0) break; 
			int mindis=n;
			for(id=head[u]; id!=-1; id=edge[id].next){
				v=edge[id].v;
				if(edge[id].w>0 && dis[v] < mindis){
					mindis = dis[v];
					cur[u]=id;
				}
			}
			dis[u] = mindis + 1;
			gap[dis[u]]++;
			if(u!=s)u=pre[u];
		}
	}
	return max_flow;
}

int in[N];
int main(){
	int Cas,tt=0;
	scanf("%d",&Cas);
	while(Cas--){
		scanf("%d %d",&n,&m);
		tot=sum=s=0;
		memset(head,-1,sizeof(head));
		memset(in,0,sizeof(in));
		t = n+1;
		int sum_flow =0;
		rep(i,0,m){
			int u,v,b,d;
			scanf("%d %d %d %d",&u,&v,&b,&d);
			addEdge(u,v,d);
			in[v]+=b;
			in[u]-=b;
		}
		rep(i,1,n+1){
			if(in[i] > 0){
				sum_flow += in[i];
				addEdge(s,i,in[i]);
			}else{
				addEdge(i,t,-in[i]);
			}
		}
		int ans_flow = SAP(s,t,t+1);
		printf("Case #%d: ",++tt);
		if(ans_flow == sum_flow) puts("happy");
		else puts("unhappy");
	}
	return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值