结合hdu3549,谈谈个人对 最大流 和 Edmond—Karp 算法的理解

题目:hdu 3549

大意:网络流求最大流(模板题)

下面是对最大流的理解

假如说有A,B,C,D三个点,A->B 有3 的流量,B->D有2的流量,A->C有3的流量,C->D有2的流量,B->C有3的流量,那么如何求A->D的最大流量呢?如图所示:

很明显用肉眼能看出来A->B->D+A->C->D=4就是答案,那么如何用程序来实现呢?

假如使用搜索的方法(bfs,dfs都行,但是一般来说bfs会比dfs快,并且这道题用dfs会超时),从A开始搜索可以走的边,搜索到B,C,然后以他们为起点继续搜索,搜索到D,达到终点,再把每条线路中路线的最小值加起来(2+2),就是答案了,吗?

有一种情况,假如程序在以B为起点的时候搜索,得到C,然后以C为起点搜索,进入D,噢,刚好一条线,answer=2,没了。

机器搜索得出来的路线不一定就是最优解,那么如何解决这个问题呢。。

答案就是在计算机每走一条边的时候为那条边加上一条反向的边,数值等于原来那条边上使用的流量,如图

这样机器在下一次搜索的时候,就依然可以得到A->C->B->D这条路,answer=4,就是答案了。那么为什么这么做是正确的呢

我们可以用最小割来证明,但是现在先用一种我自己的理解来解释

我们只有找到一条完整的从起点到终点的路的时候,才可以算是找到一条路,因此假如我生成了一条从C->B的反向路,要是找不到从B到终点的路,那么这一条反向路也用不到,因此要用到生成的反向路必须在反向路的另一端能够到达终点,也就是B要到达终点。假如B能到达终点,那么 A->B->C->D 和 A->C->B->D 这两条路是不是等于 A->B->D 等于 A->C->D 这两条路了呢,毕竟你将两种走法相比较,bc 和 cb 因为这两条路的使用量是一样的(都是2),也就是总的数值都没变。

下面说说我对Edmond-Karp算法的理解

算法使用的是bfs,从起点开始宽搜,找到下一个点之后记录从点的移动轨迹

比如这道题的话使用一个pre数组,从A搜索到B之后让pre[B]=A

接着每搜寻到一条边,就找到整条边的最小值(A->B->D 最小值就是2),累计答案,并且在原图修改最小值且建立相反边(通过pre数组)

如此重复直到找不到边

输出答案

下面是那道题目的代码

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int N,M;
int flow[17][17],min_flow[17],pre[17];//flow的话时记录全体的边,min_flow[i]代表i以及i之前的边的最小值 
int BFS(){ 
	memset(pre,-1,sizeof(pre)); //每次找都要重置 
	queue<int> Q;
	Q.push(1);
	min_flow[1]=INF;  
	while(!Q.empty()){
		int ind=Q.front();
		Q.pop();
		for(int i=1;i<=N;i++){
			if(i!=1&&flow[ind][i]>0&&pre[i]==-1){
				Q.push(i);
				min_flow[i]=min(min_flow[ind],flow[ind][i]);  //min_flow 转移方程 
				pre[i]=ind;
			}
		}
	}
	if(pre[N]==-1) return 0;
	else return min_flow[N];
}
int main(){
	int T; cin>>T;
	for(int cnt=1;cnt<=T;cnt++){
		memset(flow,0,sizeof(flow));
		scanf("%d %d",&N,&M);
		for(int i=1;i<=M;i++){
			int x,y,c; scanf("%d %d %d",&x,&y,&c);
			flow[x][y]+=c; //防止给重复的边,此时要加上,比如 1 3 2和1 3 2 那么就是 1 3 4 
		}
		int delta=-1,max_flow=0; //delta 是每次找到一条边时边的最小值  
		while(delta=BFS(),delta!=0){
			memset(min_flow,INF,sizeof(min_flow));
			int sto=N;
			while(pre[sto]!=-1){  
				flow[pre[sto]][sto]-=delta;
				flow[sto][pre[sto]]+=delta;
				sto=pre[sto];
			}
			max_flow+=delta;
		}
		printf("Case %d: %d\n",cnt,max_flow);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43191865/article/details/88393953
今日推荐