最大流 Ford-Fulkerson 算法

Ford-Fulkerson 算法

基本思想是从任何一个可行流开始,沿增广路径对流进行增广,然后不断重复此过程,直到网络中不存在增广路径为止。

0.流网络G=(V,E)上的一个流的三个条件

  • 容量约束: f(u,v)≤c(u,v) 对∀uv∈E成立
  • 反对称性: f(u,v) = - f(v,u)
  • 守恒约束: Σ u ∈ V Σ_{u∈V} ΣuV f ( u , v ) f(u,v) f(u,v)对任意 u ∈ u∈ u V V V-{ s , t s,t s,t}成立

1.剩余网络(余图)

简单来说就是网络的总可承载流量-现有的流量,所得到的剩余网络。
给定图 G G G中的流 f f f
余图 G f G_f Gf
同样的结点,中间结点和s,t
求余图的流程:

  • 对于每条边 e e e 满足 c e c_e ce > f ( e ) f(e) f(e) 赋给权重 c e c_e ce - f ( e ) f(e) f(e) (剩余容量)
  • 对于每条边 e = ( u , v ) e = (u,v) e=(u,v) 给其逆向边 ( v , u ) (v,u) (v,u)赋给权重 f ( e ) f(e) f(e) (剩余容量,如果 f ( e ) = 0 f(e)=0 f(e)=0便不赋予)

通俗来讲,就是先把这条边按边的容量方向取反,如果这条边之前存在流量并且没有用完的话,就用总容量-已用流量作为这条边的补,加入剩余网络中。

比如
如下图所示:
以中间那个为例(u到v),u到v的容量是30,实际上只用了20,那么从u到v的管道还剩10,所以剩余网络中就有一条从u到v值为10的边,反向(从v到u)的20是用管道的总容量30减去从u到v的管道10得到的

在这里插入图片描述
案例2:剩余网络
在这里插入图片描述

2.增广路径

给定一个网络G,令 f f f为图 G G G的一个流,则称剩余网络 G f G_f Gf,中从 s s s t t t的一条有向路径 p p p为增广路径。

就是在剩余网络中从源点到汇点找一条路径

给定图 G G G中的流 f f f,对应的余图 G f G_f Gf

  1. 找到余图中的一条新流,该流通过一条没有重复结点的路径并且值和该路径上的最小容量相等(增广路径)
  2. 沿着路径更新余图

基于之前的余图,找到新的流,如下图所示,为了更好的区分,再放一张之前的余图
在这里插入图片描述

在这里插入图片描述
对刚才的剩余网络,我们寻找红色标记的一条增广路径如图所示:
在这里插入图片描述

如果我们利用增广路径进行扩展的话,显然还是满足容量约束条件的

Ford-Fulkerson 算法思想

从任何一个可行流开始,沿增广路径对流进行增广,然后不断重复此过程,直到网络中不存在增广路径为止。

其伪代码如下:

对于所有e初始化 f(e) = 0
	While 余图中存在s-t 路径 P:
		沿着路径P增广  f  得到新的 f‘  和新的余图 

沿着P增广  f  :
	找到路径的最小容量
	沿着路径修改权重

3.网络的割

给定一个网络 G = ( V , E ) G=(V,E) G=(V,E) ,网络中的一个割 ( S , T ) (S,T) (S,T)是把网络G的顶点集V分成两个子集 S S S T = V − S T=V-S T=VS且s ∈ \in S , t ∈ \in T (一个包含源点,一个包含汇点),
其中流过割 ( S , T ) (S,T) (S,T)的容量记为 c ( S , T ) c(S,T) c(S,T),定义为割 ( S , T ) (S,T) (S,T)中流过分界线的容量之和
流过割 ( S , T ) (S,T) (S,T)的流量记为 f f f ( S , T ) (S,T) (S,T) ,定义为割 ( S , T ) (S,T) (S,T)中流过分界线的现有流量之和。
例如:
在这里插入图片描述
有推论:
网络G中任意流f的值被G的任意割的容量所限制,即 ∣ f ∣ ≤ c ( S , T ) |f|≤ c(S, T) fc(S,T)

4.最大流最小割定理

增广路定理:网络达到最大流当且仅当剩余网络中没有增广路径,这也是 Ford-Fulkerson 算法的基础

最小割等于最大流

给定一个网络 G = ( V , E ) G = (V,E) G=(V,E) ,令 f 为 G 的流,则下列三个
结论相互等价:

  1. 存在一个割(S, T) ,使得 ∣ f ∣ = c ( S , T ) |f|= c(S, T) f=c(S,T)
  2. f 是G的最大流;
  3. 剩余网络 G f G_f Gf不存在增广路径

是指在一个网络流中,能够从源点到达汇点的最大流量等于如果从网络中移除就能够导致网络流中断的边的集合的最小容量和。即在任何网络中,最大流的值等于最小割的容量。

形象地理解一下:

好比你家是汇 自来水厂(有需要的同学可以把自来水厂当成银行之类 以下类似)是源
然后自来水厂和你家之间修了很多条水管子接在一起 水管子规格不一 有的容量大 有的容量小
然后问自来水厂开闸放水 你家收到水的最大流量是多少
如果自来水厂停水了 你家那的流量就是0 当然不是最大的流量
但是你给自来水厂交了100w美金 自来水厂拼命水管里通水 但是你家的流量也就那么多不变了 这时就达到了最大流

割集好比是一个恐怖分子, 把你家和自来水厂之间的水管网络砍断了一些 然后自来水厂无论怎么放水 水都只能从水管断口哗哗流走了 你家就停水了
割的大小应该是恐怖分子应该关心的事 毕竟细管子好割一些 而最小割花的力气最小
具体的证明分三部分

1.任意一个流都小于等于任意一个割
这个很好理解 自来水公司随便给你家通点水 构成一个流
恐怖分子随便砍几刀 砍出一个割
由于容量限制 每一根的被砍的水管子流出的水流量都小于管子的容量
每一根被砍的水管的水本来都要到你家的 现在流到外面 加起来得到的流量还是等于原来的流
管子的容量加起来就是割 所以流小于等于割
由于上面的流和割都是任意构造的 所以任意一个流小于任意一个割

2.构造出一个流等于一个割
当达到最大流时 根据增广路定理
剩余网络中s到t已经没有通路了 否则还能继续增广
我们把s能到的的点集设为S 不能到的点集为T
构造出一个割集 C [ S , T ] C[S,T] C[S,T] S到T的边必然满流 否则就能继续增广
这些满流边的流量和就是当前的流即最大流
把这些满流边作为割 就构造出了一个和最大流相等的割

3.最大流等于最小割
设相等的流和割分别为 F m F_m Fm C m C_m Cm
则因为任意一个流小于等于任意一个割
任意 F F F F m F_m Fm= C m C_m Cm≤任意 C C C
定理说明完成

引用:[Poj 1459网络流(一) {基本概念与算法}

##伪代码:

FordFulkerson(G, s, t, c)
//初始化
 for 每一条路径 (u,v) ∈E do
	 f (u,v)0 //初始化f(e)=0
	 Gf ←G //初始化剩余网络
//查找增广路径
 while Gf中存在一条增广路径 p do
  	cf(p)=min{cf(u,v)| uv是p上的边} //cf(p) 作为 p 路径上的最小容量(瓶颈容量)
	for each edge (u,v) in p do
	 	f (u,v) ← f (u,v)+ cf(p) //讲选择的增广路径加入图中,更新边的流量
 
 最后还需要更新剩余网络Gf

案例:对于网络:
在这里插入图片描述
计算剩余网络:
在这里插入图片描述
选择增广路径
在这里插入图片描述
然后增加对应的流量即可
在这里插入图片描述
之后循环往复,直到找不到新的增广路径即可

1.最多要增广多少次?
可以证明 最多O(VE)次增广 可以达到最大流 证明略

2.如何找到一条增广路?
先明确什么是增广路 增广路是这样一条从s到t的路径 路径上每条边残留容量都为正
把残留容量为正的边设为可行的边 那么我们就可以用简单的BFS得到边数最少的增广路

3.如何增广?
BFS得到增广路之后 这条增广路能够增广的流值 是路径上最小残留容量边决定的
把这个最小残留容量MinCap值加到最大流值Flow上 同时路径上每条边的残留容量值减去MinCap
最后 路径上每条边的反向边残留容量值要加上MinCap

显然算法的运行时间取决于增广路径 p该如何确定,使用BFS或DFS查找增广路径的时间为O(V+E’)=O(E)
可以证明最多使用O(VE)次增广 可以达到最大流,如果算法用BFS选择增广路径(Edmonds-Karp算法) , 则算法的时间复杂度为O( V E 2 VE^2 VE2)

例题:双核CPU网络流问题

随着越来越多的计算机配备了双核 CPU,TinySoft 公司的首席技术 官塞塔格利布决定更新他们著名的产品——SWODNIW。 这个例程由 N 个模块组成,每个模块都应该在某个内核中运行。估计了在 两个内核上执行所有例程的成本。我们把它们定义为 Ai 和 Bi。同时,M 对模块 需要进行数据交换。如果它们在同一个内核上运行,则可以忽略此操作的成本。 否则,就需要额外的费用。你应该明智地安排,把总费用降到最低。请写出伪代 码并分析算法复杂度。
这个题乍一看是一个动态规划问题,其实还是个网络流(二分匹配),只需要将两个核心看作是源点和汇点,然后寻找最小割就行了

在这里插入图片描述
用一个割将图一刀劈开,保证核心S和T属于不同的划分,且流经割的流量最小;如果两个进程在同一个划分,那么这两个进程没有任何流量会流经这个割,否则的话就要计算这个额外的流量(因为割划断了两个进程之间联系的边),也就把这两个节点放到了不同的CPU运行

显然节点i不能同时属于S和T,i要么属于s的划分,要么属于T的划分,如果属于S的话,则i到T的边必然被割集经过(选择在T执行);如果属于T的话,则i到S的边必然被割集经过(选择在S执行),因为割是最小割,所以任务安排的代价也是最小的,因此对于i,我们让割经过这条边,这条边在两个划分之间

划分割需要划过很多边,使得划分的边的总大小最小就能找到一个对进行i和j的代价最小的安排方案

割划过的边就是我们需要支付的代价最小割就对应最小的代价

然后再跑一边最大流算法就可以了
伪代码

FordFulkerson(G, s, t, c)
//初始化
 for 每一条路径 (u,v) ∈E do
	 f (u,v)0 //初始化f(e)=0
	 Gf ←G //初始化剩余网络
//查找增广路径
 while Gf中存在一条增广路径 p do
  	cf(p)=min{cf(u,v)| uv是p上的边} //cf(p) 作为 p 路径上的最小容量(瓶颈容量)
	for each edge (u,v) in p do
	 	f (u,v) ← f (u,v)+ cf(p) //讲选择的增广路径加入图中,更新边的流量
 
 Gf<-newGf
  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Ford-Fulkerson算法是一种解决最大流问题的算法,它通过不断寻找增广路径来增加流量,直到无法找到增广路径为止。在Matlab中,可以使用图论工具箱中的函数来实现Ford-Fulkerson算法,例如使用graph和maxflow函数。具体实现方法可以参考Matlab官方文档或相关教程。 ### 回答2: Ford-Fulkerson算法是求解最大流问题的一种经典算法,用于确定一个网络中从源节点到汇节点的最大可行流量。下面我将简要介绍如何使用Matlab实现Ford-Fulkerson算法。 首先,我们需要定义一个图结构来表示网络。可以使用邻接矩阵来表示有向图,其中矩阵元素表示边的容量。源节点可以用一个预先定义的节点索引表示,汇节点也可以用另一个预先定义的节点索引表示。 接下来,我们可以实现Ford-Fulkerson算法的关键步骤。算法的主要思想是在剩余网络上找到增广路径,并在这条路径上增加流量,直到不能找到增广路径为止。 具体实现中可以使用深度优先搜索(DFS)或广度优先搜索(BFS)来找到增广路径。在每一次搜索过程中,我们需要判断当前节点是否已经被访问过,并且是否还可以通过当前边增加流量。 在找到增广路径后,我们可以计算出该路径上的最小容量(也称作瓶颈容量),并将该容量从剩余网络中减去。随后,我们将该容量添加到流网络中,并继续寻找新的增广路径。 当无法找到增广路径时,算法结束并返回最大流量值。最大流量值等于从源节点发出的所有流量之和。 综上所述,以上是在Matlab中实现Ford-Fulkerson算法的基本步骤。当然,具体实现中还需要考虑一些细节问题,并且可能需要调用一些Matlab内置的图算法函数来辅助实现。 ### 回答3: Ford-Fulkerson算法是用于求解最大流问题的一种常见算法,适用于有向图。算法的基本思想是不断在剩余网络中寻找一条增广路径,然后更新流量分布,直到无法找到增广路径为止。 在MATLAB中,可以使用图算法工具箱中的函数来实现Ford-Fulkerson算法。具体步骤如下: 1. 首先,需要创建一个有向图对象,并定义图中的节点和边。可以使用Graph对象来进行操作。 2. 然后,设置源节点和汇节点,即确定最大流的起点和终点。 3. 接下来,需要定义图中各个边的初始容量。可以使用addedge函数来添加边,并设置其容量。 4. 之后,可以使用fordfulkerson函数来求解最大流。该函数会返回一个最大流值,同时也会更新图中各个边的流量。 5. 最后,可以使用findedge函数来查找某条边的流量。该函数需要指定边的起点和终点节点,返回对应边的流量值。 需要注意的是,Ford-Fulkerson算法的复杂度较高,最坏情况下为O(f * m),其中f为最大流值,m为边的数量。因此,在处理大规模图的情况下可能会面临一定的挑战。 以上是用MATLAB实现Ford-Fulkerson算法的简要过程。通过使用MATLAB的图算法工具箱,可以方便地对最大流问题进行求解。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值