网络最大流问题之Ford-Fulkerson算法原理详解

前言

  最大流问题是网络优化中典型的问题,用形象的语言来描述就是在满足容量约束的前提下将尽可能多的流从源节点(始点)到汇节点(终点)。解决此问题的经典方法很多,本文介绍广为人熟知的Ford-Fulkerson算法,来解决最大流问题。尽管网上关于此问题的文章多如牛毛,但笔者希望结合自己学习过程中对算法的理解,给予算法最清晰的介绍,希望对大家有帮助。(笔者曾尝试使用java来实现,但最终因用java实现和使用图太麻烦了,又不想重新用python来实现,故放弃,以后的实现估计会采用python而不是java,java毕竟不适合写图相关算法)。

 

一、知识准备

  学习此算法前建议读者学习网络流相关知识和基本概念,一些需要了解的概念和知识先罗列如下

  1、可增广路

  2、最大流最小割定理

  3、图的割集

  4、饱和割集

  5、可行流向量

  6、节点的散度

  7、前向后向边

  

 

二、可增广路搜索算法

  对于k=0,1,..., 给定Tk, 若Tk为空集或者t∈Tk则算法终止。否则,令

    Tk+1 = { Tk | 存在节点m∈Tk, 以及边(m, n) 满足xmn < cmn, 或者边(n, m) 满足 bnm<xnm},

   (其中节点数为n,bnm和cnm为边mn容量的最小和最大值,xmn为边的流量, Tk+1集合的节点不能属于T其他集合节点)

  上式的含义即为Tk+1为在集合Tk中所有节点满足可增广路条件的相邻的节点组成的集合,当然,这些节点不能包括已经存在其他T集合中的节点。

  当算法终止时,最后一个集合Tk有两种情况(假设s为起点, t为终点):

  (1) 最后一个集合Tk包含t,此时从t向前标记即可构造从s到t的简单可增广路。即从T1,T2,T3,....,Tk中每个取一个节点的路

  (2)最后一个集合Tk为空集,此时得到一个分离s和t的饱和割集

  现举例说明,如下图(容量下限(最小值),流量,容量上限(最大值))标在每条边旁

  

  1为源点,6为汇点。开始T0只有1个节点,就是节点1。接下来从和T0中节点,也就是节点1相邻的节点2和3开始。边12,流量为0,为前向边,满足流量小于容量上限;边13也为前向边,满足流量小于上限(0 < 1)。所以节点2和节点3组成T1。然后考虑以节点2和节点3来寻找T2,原理和前面一致,其中边35,为后向边,流量为2,大于容量下限1,所以节点5添加到T2,。到最后T3,集合包含6,终止。此时增广路为(1,3,5,6)。

  现在看另一图,只是把边56的流量改为了0,此时后向边56不满足流量大于下限,所以T3为空集。此时存在饱和割集{S, N-S}分离1和6,其中S = {1,2,3,4,5},是所有集合Tk的并集

  

 

三、Ford-Fulkerson算法

  在了解了可增广路搜索算法后,现在正式进入本文的主题,Ford-Fulkerson算法。该算法在每次迭代中改进原费用(s的散度),因此是原费用改进型算法。算法思想是,给定可行流向量x(即满足容量可行且除了s和t之外节点的散度为零,即节点流入和流出相等,的流向量),以及对于x可增广的从s到t的路P,就可以增进P的前向边(i,j)的流量并减小P的后向边(i,j)的流量。流量增量的最大值为  

  δ = min{   {cij - xij | (i, j) ∈ P+},    {xij - bij | (i, j) ∈ P-}  }, 其中P+是P的前向边的集合, P-是P的后向边的集合。

  由此得到的流向量y由

    yij = :xij + δ 如果(i, j) ∈ P+,

        xij  - δ 如果(i,j)   ∈P-,

  算法的迭代步骤

  使用可增广路搜索算法实现下述两种情况之一:

  (1)、得到将s和t分离的饱和割集

  (2)、得到从s到t的x的可增广路P。

  在情况1下,算法终止;此时的流向量即为所求。在情况2下,沿着P进行增广,并进行下一次迭代。每次增广时,算法通过增广增量δ改进原费用(s的散度)。现在以例子说明

  初始图,如图1。搜索到增广路(1, 2, 5),路12和路25为正向边,求δ=min{ c12- x12, c25- x25}为1。如图2

    图1

  图2

对增广路中的所有边x12和x25使用δ改进费用,因为均为正向边,有新的流量为x12=0 + 1 = 1, x25= 0 + 1 = 1。费用改进后如图3。费用改进后继续寻找增广路,如图4。

图3

      图4

迭代

  图5

  图6

迭代

  图7

  图8

在最后一次费用改进后,已找不到增广路。其中T0包含节点1,T1包含节点2,T3包含节点3,因此饱和割集为[{1, 2, 3}, {4, 5}]。割集容量即为最大容量,即5=c24 + c34 + c25  = 5

图9

 

四、

  在学习此算法时,笔者已经尽力描述算法的主要内容了。由于需要有一些图论的知识作为辅助,加上算法有些复杂,所以结合文中例子效果会更好。

 

五、知识相关

  最短路径算法之Dijkstra算法(java实现)

 

        

转载于:https://www.cnblogs.com/junyuhuang/p/4566802.html

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Ford-Fulkerson算法求解最大流问题的一种经典算法。以下是一个基于增广路思想的Ford-Fulkerson算法的代码: ``` // 基于邻接矩阵的Ford-Fulkerson算法实现 #include <iostream> #include <queue> #include <cstring> using namespace std; const int MAXN = 100; // 最大顶点数 const int INF = 0x3f3f3f3f; // 表示无穷大 int n, m; // n表示顶点数,m表示边数 int s, t; // s表示源点,t表示汇点 int cap[MAXN][MAXN]; // 表示容量 int flow[MAXN][MAXN]; // 表示量 int pre[MAXN]; // 表示前驱节点 int bfs() { memset(pre, -1, sizeof(pre)); // 初始化前驱节点数组 queue<int> q; q.push(s); pre[s] = -2; while (!q.empty()) { int u = q.front(); q.pop(); for (int v = 0; v < n; ++v) { if (pre[v] == -1 && cap[u][v] > flow[u][v]) { pre[v] = u; if (v == t) return 1; q.push(v); } } } return 0; } int maxFlow() { int ans = 0; while (bfs()) { int minflow = INF; for (int u = t; u != s; u = pre[u]) { int v = pre[u]; minflow = min(minflow, cap[v][u] - flow[v][u]); } for (int u = t; u != s; u = pre[u]) { int v = pre[u]; flow[v][u] += minflow; flow[u][v] -= minflow; } ans += minflow; } return ans; } int main() { cin >> n >> m >> s >> t; memset(cap, 0, sizeof(cap)); memset(flow, 0, sizeof(flow)); for (int i = 0; i < m; ++i) { int u, v, c; cin >> u >> v >> c; cap[u][v] += c; // 注意有可能存在重边 } cout << maxFlow() << endl; return 0; } ``` 算法思路: 1. 初始化量为0; 2. 在剩余容量大于0的情况下,寻找增广路: - 从源点s开始,使用BFS寻找一条增广路; - 如果找到增广路,计算增广路上的最小剩余容量minflow,更新量; 3. 最大就是所有增广路上的最小剩余容量之和。 其中,增广路的定义是指从源点到汇点路径上,剩余容量均大于0的路径。在Ford-Fulkerson算法中,每次都需要寻找一条增广路来更新量,直到无法再找到增广路为止。这个过程中,每次找到的增广路都可以使得量增加,因此最终的量是不断增加的。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值