在算法导论中对求解最大流问题给出了一般性的解决方法,但并没有涉及到具体的实现。在这里我还是重新的对求解最大流的思想进行一般性的描述,然后再给出具体的实现。

Ford-Fulkerson方法依赖于三种重要思想,这三个思想就是在上一篇网络流基础中提到的:残留网络,增广路径和割。Ford-Fulkerson方法是一种迭代的方法。开始时,对所有的u,v∈V有f(u,v)=0,即初始状态时流的值为0。在每次迭代中,可通过寻找一条“增广路径”来增加流值。增广路径可以看成是从源点s到汇点t之间的一条路径,沿该路径可以压入更多的流,从而增加流的值。反复进行这一过程,直至增广路径都被找出来,根据最大流最小割定理,当不包含增广路径时,f是G中的一个最大流。在算法导论中给出的Ford-Fulkerson实现代码如下:

FORD_FULKERSON(G,s,t)
     1   for each edge(u,v)∈E[G]
     2        do f[u,v] <— 0
     3            f[v,u] <— 0
     4   while there exists a path p from s to t in the residual network Gf
     5        do cf(p) <— min{ cf(u,v) : (u,v) is in p }
     6        for each edge(u,v) in p
     7             do f[u,v] <— f[u,v]+cf(p)         //对于在增广路径上的正向的边,加上增加的流
     8                  f[v,u] <— -f[u,v]                //对于反向的边,根据反对称性求

第1~3行初始化各条边的流为0,第4~8就是不断在残留网络Gf中寻找增广路径,并沿着增广路径的方向更新流的值,直到找不到增广路径为止。而最后的最大流也就是每次增加的流值cf(p)之和。在实际的实现过程中,我们可以对上述代码做些调整来达到更好的效果。如果我们采用上面的方法,我们就要保存两个数组,一个是每条边的容量数组c,一个就是上面的每条边的流值数组f,在增广路径中判断顶点u到v是否相同时我们必须判断c[u][v]-f[u][v]是否大于0,但是因为在寻找增广路径时是对残留网络进行查找,所以我们可以只保存一个数组c来表示残留网络的每条边的容量就可以了,这样我们在2~3行的初始化时,初始化每条边的残留网络的容量为G的每条边的容量(因为每条边的初始流值为0)。而更新时,改变7~8行的操作,对于在残留网络上的边(u,v)执行c[u][v]-=cf(p),而对其反向的边(v,u)执行c[v][u]+=cf(p)即可。

现在剩下的最关键问题就是如何寻找增广路径。而Ford-Fulkerson方法的运行时间也取决于如何确定第4行中的增广路径。如果选择的方法不好,就有可能每次增加的流非常少,而算法运行时间非常长,甚至无法终止。对增广路径的寻找方法的不同形成了求最大流的不同算法,这也是Ford-Fulkerson被称之为“方法”而不是“算法”的原因。下面将给出Ford-Fulkerson方法的具体实现细节:

[cpp] view plaincopy
  1. int c[MAX][MAX];  //残留网络容量
  2. int pre[MAX];  //保存增广路径上的点的前驱顶点
  3. bool visit[MAX];
  4. int Ford_Fulkerson(int src,int des,int n){   //src:源点 des:汇点 n:顶点个数
  5. int i,_min,total=0;
  6. while(true){
  7. if(!Augmenting_Path(src,des,n))return total; //如果找不到增广路就返回,在具体实现时替换函数名
  8. _min=(1<<30);
  9. i=des;
  10. while(i!=src){   //通过pre数组查找增广路径上的边,求出残留容量的最小值
  11. if(_min>c[pre[i]][i])_min=c[pre[i]][i];
  12. i=pre[i];
  13. }
  14. i=des;
  15. while(i!=src){    //再次遍历,更新增广路径上边的流值
  16. c[pre[i]][i]-=_min;
  17. c[i][pre[i]]+=_min;
  18. i=pre[i];
  19. }
  20. total+=_min;     //每次加上更新的值
  21. }
  22. }

Edmonds-Karp算法实际上就是采用广度优先搜索来实现对增广路径的p的计算,代码如下:

[cpp] view plaincopy
  1. bool Edmonds_Karp(int src,int des,int n){
  2. int v,i;
  3. for(i=0;i<n;i++)visit[i]=false;
  4. front=rear=0;     //初始化
  5. que[rear++]=src;
  6. visit[src]=true;
  7. while(front!=rear){     //将源点进队后开始广搜的操作
  8. v=que[front++];
  9. //这里如果采用邻接表的链表实现会有更好的效率,但是要注意(u,v)或(v,u)有任何一条
  10. //边存在于原网络流中,那么邻接表中既要包含(u,v)也要包含(v,u)
  11. for(i=0;i<n;i++){
  12. if(!visit[i]&&c[v][i]){  //只有残留容量大于0时才存在边
  13. que[rear++]=i;
  14. visit[i]=true;
  15. pre[i]=v;
  16. if(i==des)return true;   //如果已经到达汇点,说明存在增广路径返回true
  17. }
  18. }
  19. }
  20. return false;
  21. }

Ford-Fulkerson Edmonds-Karp算法相关推荐

  1. C++Rabin Karp算法字符串快速查找(附完整源码)

    C++Rabin Karp算法字符串快速查找 C++Rabin Karp算法字符串快速查找完整源码(定义,实现,main函数测试) C++Rabin Karp算法字符串快速查找完整源码(定义,实现,m ...

  2. C++实现bellman ford贝尔曼-福特算法(最短路径)(附完整源码)

    C++实现bellman ford贝尔曼-福特算法 实现bellman ford贝尔曼-福特算法的完整源码(定义,实现,main函数测试) 实现bellman ford贝尔曼-福特算法的完整源码(定义 ...

  3. Rabin Karp 算法详解及Python实现

    目录 一.Rabin Karp 核心思路 二.字符串如何做哈希映射 三.借助前缀和列表计算滑动窗口 四.leetcode28. 代码实现 Rabin Karp 算法是用于实现字符串的模式匹配,先看le ...

  4. C++ edmond karp和ford fulkerson求最大流算法(附完整源码)

    C++实现hopcroft karp霍普克洛夫特-卡普算法 C++实现hopcroft karp霍普克洛夫特-卡普算法完整源码(定义,实现,main函数测试) C++实现hopcroft karp霍普 ...

  5. leetcode 1044. Longest Duplicate Substring | 1044. 最长重复子串(Rabin Karp算法)

    题目 https://leetcode.com/problems/longest-duplicate-substring/ 题解 这题暴力超时,看了 Related Topics,以及 Hint,主要 ...

  6. 算法艺术——网络最大流

    女强人:http://blog.csdn.net/abcjennifer/article/details/5556455 USACO 4.2.1 Ditch 网络最大流问题算法小结 通过 USACO ...

  7. ICPC-图论知识与算法要览

    1.图定义(Definitions in graph theory) 1)图(Graph) 2)有向图(Directed graph) 3)图数据表示 邻接矩阵(Adjacency Matrix),邻 ...

  8. 增广路算法 (最大流问题)

    Edmonds-Karp算法: 计算机科学中, Edmonds–Karp算法通过实现Ford–Fulkerson算法来计算网络中的最大流,其时间复杂度为O(V E2). 该算法由Yefim (Chai ...

  9. 10种算法一文打尽!基本图表算法的视觉化阐释

    图源:unsplash 来源:读芯术 在社交媒体网络.网页和链接.GPS中位置和路线等真实场景中,图表已成为一种强大的建模和捕获数据手段,如果一组对象相互关联,则可以用图表来表示. 本文就将简要解释1 ...

  10. 算法导论 CLRS 第26章 最大流 Maximum flow C#

    2021/11/26 第六部分 图算法 第22章 基本的图算法 图数据结构设计 出度.入度和度 有向图 出度≠入度 先初始化出度,再初始化入度,u.入度=u.AdjList.length-u.out_ ...

最新文章

  1. python第三方库numpy-python第三方库之numpy基础
  2. Oracle在线重定义
  3. YJango的循环神经网络——实现LSTM YJango的循环神经网络——实现LSTM YJango YJango 7 个月前 介绍 描述最常用的RNN实现方式:Long-Short Term Me
  4. Python打开文件,将list、numpy数组内容写入txt文件中
  5. python shape函数_Perlin噪声和Python的ctypes
  6. java应用重启导致数据丢失_java – 在重新启动应用程序后从SharedPreferences恢复时设置丢失数据...
  7. Java笔记(3) - 使用Spring Cloud Zookeeper + Feign实现服务发现
  8. how is SAP ui5 formatter resolved
  9. 第九章 魔法方法、特性和迭代器
  10. Skype 释出新的 Linux 客户端
  11. 一起谈.NET技术,抛砖引玉:我看微软.NET各子技术领域之应用前景
  12. azure web应用部署_使用Visual Studio Code将Python应用程序部署到Azure Functions
  13. oracle 普通数据文件备份与恢复
  14. 解决vue页面刷新或者后退参数丢失的问题
  15. 算法分析-插入排序INSERT_SORT与选择排序SELECT_SORT【线性方法】
  16. python语言命名规则的是()_python语言命名规则是什么?
  17. json字符串-单、双引号
  18. DNS-实验3_委派子域和转发
  19. 闲话英特尔发展史中的尴尬瞬间(1)-名不副实的MMX
  20. 多图站点性能优化:图片压缩、图片缩放、HTTP2、CDN、网络传输优化、图片懒加载预加载、响应式图片

热门文章

  1. 自学elastic search
  2. [bzoj4025] 二分图
  3. 【转】opengl的一些小问题
  4. loadrunner中面向目标场景的设计
  5. Android 常见 Memory Leak 原因及解决办法总结
  6. 201621123083 《Java程序设计》第9周学习总结
  7. 配置visual studio code进行asp.net core rc2的开发(转载jeffreywu)
  8. 可能促使您决定创建自定义数据绑定控件的一些原因:
  9. Affine层/Softmax层的实现
  10. mysql not in 或 in 优化