网络流之最大流问题

1.什么是网络流?

类比一张水域网络,每条河流都有限定最大流过的水流,现在我们要找从水源到终点最多可以流多少水。水源叫做源点,而终点叫做汇点。

2.什么是增广路?

我们从A点可以流20mol水到B点,但是如果只流了14mol,从A到B的增广路就是6mol,也就是还能流6mol水到B点。当然,为了方便后悔,我们再弄一条从B到A的增广路,流量是14mol,意味着我们可以撤走这14mol的水。

3.最大流问题的做法?

常用的算法是增广路算法,就是每次都找一条增广路,然后把增广路上的流量都增加(或者容量都减少),注意反向边要进行逆操作。这样这样,找到到不了汇点时,我们就已经充分利用了每一条路,这样就得到了最大流。而找增广路的过程,用dfs和bfs都是可以的,我用的是bfs。

4.代码

题目:HDU3549

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<climits>
using namespace std;
int flow[17][17];
int fa[17],liu[17],que[201];
int n,m,T;
int bfs(){
	int i,j,head=1,tail=1,from;
	que[1]=1;liu[1]=INT_MAX;
	memset(fa,0,sizeof(fa));
	while(head<=tail){
		from=que[head];
		if(from==n)break;
		for(i=1;i<=n;i++){
			if(flow[from][i]>0&&fa[i]==0){
				liu[i]=min(liu[from],flow[from][i]);
				fa[i]=from;
				tail++;que[tail]=i;
			}
		}
		head++;
	}
	if(fa[n]==0)return -1;
	return liu[n];
}
int find(){
	int ans=0,x,kl,last;
	kl=bfs();
	while(kl!=-1){
		ans+=kl;
		x=n;
		while(x!=1){
			last=fa[x];
			flow[last][x]-=kl;flow[x][last]+=kl;
			x=last;
		}
		kl=bfs();
	}
	return ans;
}
int main()
{
    int i,j,x,y,z,cnt=0;
    scanf("%d",&T);
    while(T){
    	memset(flow,0,sizeof(flow));
    	T--;cnt++;
    	scanf("%d%d",&n,&m);
    	for(i=1;i<=m;i++){
    		scanf("%d%d%d",&x,&y,&z);
    		flow[x][y]+=z;
    	}
    	printf("Case %d: %d\n",cnt,find());
    }
    return 0;
}


题目:HDU1532

#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<climits>
using namespace std;
int n,m;
int flow[202][202];//注意重边!
int fa[202],liu[202],que[1002];//fa:上一点,liu:从上一点流过来的流量
int bfs(){
	int i,j,head=1,tail=1,from,to;
	que[1]=1;liu[1]=INT_MAX;
	memset(fa,0,sizeof(fa));
	while(head<=tail){
		from=que[head];
		if(from==n)break;
		for(i=1;i<=n;i++){
			if(i!=from&&flow[from][i]>0&&fa[i]==0){//用fa来堵路
				liu[i]=min(liu[from],flow[from][i]);
				fa[i]=from;
				tail++;que[tail]=i;
			}
		}
		head++;
	}
	if(fa[n]==0)return -1;
	return liu[n];
}
int find(){
	int ans=0,kl,x,last,cnt=0;
	kl=bfs();
	while(kl!=-1){
		ans+=kl;x=n;
		while(x!=1){//减少容量,等于增加流量
			last=fa[x];
			flow[last][x]-=kl;flow[x][last]+=kl;
			x=last;
		}
		kl=bfs();
	}
	return ans;
}
int main()
{
    int i,j,x,y,z;
    while(scanf("%d%d",&m,&n)==2){
    	memset(flow,0,sizeof(flow));
    	for(i=1;i<=m;i++){
    		scanf("%d%d%d",&x,&y,&z);
    		flow[x][y]+=z;//不用定义相反边,因为相反边是用来后悔的,注意重边
    	}
    	printf("%d\n",find());
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值