图论(八)——网络流的最大流问题之Edmonds-Karp算法

最大流

图论(五)——网络流的最大流问题引入

增广路

为了解决最大流问题,再引入一个概念:剩余容量【c(x , y)-f(x , y)】


如果可以找到一条从源点出发,经过中间节点,流向汇点,且其中每一条边的剩余容量均大于0的路,就称这条路为一条增广路,假设可以知道这一条增广路中所有的边的最小剩余容量为p,那么对于整个网络系统而言,就可以增加一个流量为w的流从源点通过这一条路流向汇点,那么这个网络的流量就增加了w。

如果找到了所有的增广路,已经没有其他的增广路可以找时,就说明网络的流量达到了最大,此时的流量就是网络的最大流了


Edmonds-Karp增广路算法

Edmonds-Karp算法,简称为EK算法,就是不断的用BFS(显然这种问题中用BFS比用DFS快捷的多)找增广路,找到所有的增广路的时候就计算出网络的最大流了


当然,在这个过程中还要注意:除了考虑原图的所有边之外,还应该考虑所有边的反向边,这些边可能有些因为没有在图中输入,他们的原始容量为0,特别容易被忽略
这个意思就是:对于一条边(x , y)而言,如果在加入增广路的过程中流过了一个”流“,其剩余流量变成了c(x , y)-f(x , y),那么其反向边的流量也会发生变化,变成了c(y , x)-f(y , x)


图解:
增广路图解
【画的有点丑不要怪我QAQ】


代码实现:(因为还有反向边的储存,所以可以用到邻接表的”成对储存技巧“)

#include<queue>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF = 0x3f3f3f3f;
const int len_node = 2010;
const int len_edge = 20010;  //这个是要开的数组的大小,根据题目自己定就行了

int num_node,num_edge,s,t,cnt,maxflow;
int to[len_edge],edge[len_edge],head[len_node],nxt[len_edge];  //边  
int vis[len_node],minf[len_node],pre[len_node];
/*
minf:  记录每一条增广路上的最小容量
pre:  记录前驱(使得在这条增广路上每一条边由终点可以知道起点) 
*/

void init(){
	memset(head,0,sizeof(head));
	
	s=1;
	t=num_node;
	cnt=1;
	maxflow=0;
}

void addEdge(int u,int v,int w){
	//有向图 存边操作
	to[cnt]=v;
	edge[cnt]=w;
	nxt[cnt]=head[u];
	head[u]=cnt++;
	
	//成对储存 
	to[cnt]=u;
	edge[cnt]=0;
	nxt[cnt]=head[v];
	head[v]=cnt++; 
}   //因为规定了 一对边不能同时为正 所以一条边为正 另一条边就为0 

int x,y; 
bool BFS(){
	memset(vis,0,sizeof(vis));
	
	queue<int>q;
	q.push(s);
	vis[s]=1;
	minf[s]=INF;  //这个用来逐步记录这条增广路上的最小容量 
	
	while(!q.empty()){
		x=q.front();
		q.pop();
		
		for(int i=head[x];i;i=nxt[i]){
			if(edge[i]){
				y=to[i];
				if(vis[y]){
					continue;
				}
				
				minf[y]=min(minf[x],edge[i]);  //更新这个最小容量   这个是从一开始就开始更新的  所以经过这个过程之后  minf[t] 此时就是这一条增广路的最小容量 
				pre[y]=i;  //记录前驱  便于找到最长路的实际方案  在update函数中发挥作用
				q.push(y);
				vis[y]=1;
				if(y==t){
					return 1;  //找到了一条增广路了  直接返回 进行 update() 
				} 
			}
		}
	}
	
	return 0; 
} 

int p,pre_p;
void update(){  //更新增广路及其反向边的剩余容量 
	p=t;
	while(pre_p!=s){
		pre_p=pre[x];
		edge[pre_p] -= minf[t];
		edge[pre_p^1] += minf[t];
		
		p=to[pre_p^1];
	}
	
	maxflow+=minf[t];
}

int main(){
	int a,b,c;
	while(~scanf("%d%d",&num_node,&num_edge)){
		init();
		
		for(int i=1;i<=num_edge;i++){
			scanf("%d%d%d",&a,&b,&c);
			addEdge(a,b,c);
		}
		
		while( BFS() ){
			update();
		}
		
		printf("%d\n",maxflow);
	}
	
	return 0;
}

时间复杂度:O(numNode*numEdge^2)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: Edmonds-Karp算法是一种最大算法,可以在网络问题中找到最大量。Matlab是一款数学软件,可以用于求解各种数学问题,包括网络问题。可以使用Matlab编写Edmonds-Karp算法的程序或者将现有的Edmonds-Karp算法移植到Matlab中进行求解。 ### 回答2: Edmonds-Karp算法是解决最大流问题的一种经典算法。它是基于Ford-Fulkerson算法的改进版本,通过在寻找增广路径时使用BFS(广度优先搜索)来保证找到的路径是最短路径。以下是一个使用Matlab实现Edmonds-Karp算法的伪代码: 1. 输入: 邻接矩阵adjMatrix,表示图的连接关系;起始节点source和目标节点target。 2. 初始化残余容量矩阵residualCapacity,将其与adjMatrix相同并全部初始化为0。 3. 初始化最大量maxFlow为0。 4. 循环直到无法找到增广路径: 5. 使用BFS从source到target寻找增广路径,得到路径path。 6. 若无法找到增广路径,则退出循环。 7. 计算增广路径上的最小残余容量minCapacity。 8. 更新残余容量矩阵residualCapacity: - 对于路径上的每一条边(u, v),将residualCapacity[u][v]减去minCapacity。 - 对于路径上的每一条反向边(v, u),将residualCapacity[v][u]增加minCapacity。 9. 将maxFlow增加minCapacity。 10. 输出maxFlow作为最大量。 在Matlab中实现Edmonds-Karp算法,可以根据以下步骤进行编程: - 首先,使用邻接矩阵adjMatrix表示图的连接关系,可以使用Matlab中的二维数组进行表示。 - 然后,根据输入的source和target,使用BFS算法找到增广路径。可以使用队列(Queue)数据结构实现BFS。 - 计算增广路径上的最小残余容量minCapacity,可以使用带权图中的最小值函数进行计算。 - 更新残余容量矩阵residualCapacity,可以根据路径上的边进行更新操作。 - 循环直到无法找到增广路径,可以使用while循环实现。 - 输出最大量maxFlow作为结果。 总之,通过以上步骤进行编程,即可在Matlab中实现Edmonds-Karp算法来解决最大流问题。 ### 回答3: Edmonds-Karp算法是一种用于解决最大流问题算法,它是基于Ford-Fulkerson算法的改进版本。该算法通过在残余网络中不断寻找增广路径来找到最大。 在Matlab中实现Edmonds-Karp算法,可以按以下步骤进行: 1. 创建一个图表示残余网络,图中的边包含它们的容量和量。可以使用Matlab中的图论相关函数(如graph函数)创建图。 2. 初始化每条边的量为0。 3. 在残余网络中寻找增广路径,可以使用广度优先搜索(BFS)算法。从源节点开始,通过检查当前节点的邻居节点来找到增广路径。如果在残余网络中找到一条增广路径,就可以通过调整路径上的边的量来增加总量。 4. 不断重复步骤3,直到在残余网络中找不到增广路径为止,即没有可以进一步增加总量的路径。 5. 返回最大。 在Matlab中实现Edmonds-Karp算法需要对图的表示和广度优先搜索算法有一定的了解。可以使用Matlab中的图论包(如Graph and Digraph)来操作图,并使用队列数据结构来实现BFS算法。 需要注意的是,由于Edmonds-Karp算法的复杂度较高,如果图的规模比较大,算法可能需要较长的运行时间。在实际应用中,可以考虑使用其他更高效的最大算法,如Dinic算法或Push-Relabel算法

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值