Edmonds-Karp详解-基于BFS的最短增广路径

article/2025/6/29 10:30:57

Edmonds-Karp详解-基于BFS的最短增广路径与py/cpp/Java三语言实现

    • 一、网络流问题与相关概念回顾
      • 1.1 网络流问题定义
      • 1.2 关键概念
    • 二、Edmonds-Karp算法原理
      • 2.1 算法核心思想
      • 2.2 算法具体流程
    • 三、Edmonds-Karp算法的代码实现
      • 3.1 Python实现
      • 3.2 C++实现
      • 3.3 Java实现
    • 四、Edmonds-Karp算法的时间复杂度与空间复杂度分析
      • 4.1 时间复杂度
      • 4.2 空间复杂度
    • 五、Edmonds-Karp算法的应用场景
      • 5.1 资源分配
      • 5.2 网络通信
      • 5.3 交通运输
    • 总结​

网络流问题的求解算法中,Edmonds-Karp算法作为一种经典且高效的方法,在资源分配、网络通信等众多领域发挥着关键作用。它是Ford-Fulkerson算法的优化版本,通过利用广度优先搜索(BFS)寻找最短增广路径,有效避免了Ford-Fulkerson算法可能出现的低效情况,大幅提升了算法性能。本文我将详细阐述Edmonds-Karp算法的原理、实现流程,并用Python、C++和Java三种语言进行代码实现,带你全面深入地掌握这一重要算法。

一、网络流问题与相关概念回顾

1.1 网络流问题定义

网络流问题可抽象为一个有向图 G = ( V , E ) G=(V, E) G=(V,E),其中 V V V 是顶点集合, E E E 是边集合。图中存在一个源点 s s s 和一个汇点 t t t,每条边 ( u , v ) ∈ E (u, v) \in E (u,v)E 都有一个非负的容量 c ( u , v ) c(u, v) c(u,v),表示该边能够传输的最大流量。网络流问题的核心目标是在满足流量守恒原则(除源点和汇点外,每个顶点的流入流量等于流出流量)的前提下,找到从源点 s s s 到汇点 t t t 的最大流量。

1.2 关键概念

  • 流量:对于边 ( u , v ) (u, v) (u,v),其流量 f ( u , v ) f(u, v) f(u,v) 表示实际通过该边的流量,需满足 0 ≤ f ( u , v ) ≤ c ( u , v ) 0 \leq f(u, v) \leq c(u, v) 0f(u,v)c(u,v)。同时,除源点和汇点外,任意顶点 v v v 都应满足 ∑ u : ( u , v ) ∈ E f ( u , v ) = ∑ w : ( v , w ) ∈ E f ( v , w ) \sum_{u:(u,v)\in E} f(u, v) = \sum_{w:(v,w)\in E} f(v, w) u:(u,v)Ef(u,v)=w:(v,w)Ef(v,w),即流入流量等于流出流量。
  • 残留网络:给定网络 G G G 和流量 f f f,残留网络 G f G_f Gf 由原网络顶点和残留边组成。残留边 ( u , v ) (u, v) (u,v) 的容量 c f ( u , v ) c_f(u, v) cf(u,v) 定义如下:
    • ( u , v ) ∈ E (u, v) \in E (u,v)E,则 c f ( u , v ) = c ( u , v ) − f ( u , v ) c_f(u, v) = c(u, v) - f(u, v) cf(u,v)=c(u,v)f(u,v),表示该边还能容纳的额外流量。
    • ( v , u ) ∈ E (v, u) \in E (v,u)E,则 c f ( u , v ) = f ( v , u ) c_f(u, v) = f(v, u) cf(u,v)=f(v,u),意味着可以通过反向边撤销已流过的流量。
    • ( u , v ) ∉ E (u, v) \notin E (u,v)/E ( v , u ) ∉ E (v, u) \notin E (v,u)/E,则 c f ( u , v ) = 0 c_f(u, v) = 0 cf(u,v)=0
  • 增广路径:在残留网络 G f G_f Gf 中,从源点 s s s 到汇点 t t t 的简单路径称为增广路径。沿着增广路径可以增加从源点到汇点的流量,增广路径上所有残留边的最小容量就是可增加的流量值。

二、Edmonds-Karp算法原理

2.1 算法核心思想

Edmonds-Karp算法基于Ford-Fulkerson算法框架,其核心思想是在每次迭代中,利用广度优先搜索(BFS)在残留网络中寻找从源点 s s s 到汇点 t t t 的最短增广路径(这里的最短指边数最少),然后沿着该路径增加流量,更新残留网络。重复此过程,直到残留网络中不存在从源点到汇点的增广路径,此时得到的流量即为网络的最大流。通过优先选择最短增广路径,Edmonds-Karp算法避免了Ford-Fulkerson算法因选择长增广路径导致的低效情况,保证了算法的高效性和有限次迭代收敛。

2.2 算法具体流程

  1. 初始化:创建原始网络 G G G,确定源点 s s s 和汇点 t t t,将所有边的流量 f ( u , v ) f(u, v) f(u,v) 初始化为 0,构建初始的残留网络 G f G_f Gf。同时,创建一个用于记录增广路径的数组(或列表),用于存储每个顶点在增广路径上的前驱顶点。
  2. BFS寻找最短增广路径:使用BFS在残留网络 G f G_f Gf 中从源点 s s s 开始搜索,尝试找到一条到达汇点 t t t 的最短增广路径。在搜索过程中,记录每个顶点的前驱顶点,以便后续回溯得到增广路径。如果找到增广路径,则进入步骤3;若找不到,说明已达到最大流,算法结束,返回当前流量作为最大流。
  3. 计算可增加的流量:沿着找到的增广路径,计算路径上所有残留边的最小容量 δ \delta δ δ \delta δ 即为可以沿着该增广路径增加的流量值。
  4. 更新流量和残留网络:沿着增广路径更新原始网络中边的流量 f ( u , v ) f(u, v) f(u,v) 和残留网络中边的容量 c f ( u , v ) c_f(u, v) cf(u,v)。对于增广路径上的边 ( u , v ) (u, v) (u,v)
    • 在原始网络中,若 ( u , v ) (u, v) (u,v) 是正向边,则 f ( u , v ) = f ( u , v ) + δ f(u, v) = f(u, v) + \delta f(u,v)=f(u,v)+δ;若 ( u , v ) (u, v) (u,v) 是反向边,则 f ( u , v ) = f ( u , v ) − δ f(u, v) = f(u, v) - \delta f(u,v)=f(u,v)δ
    • 在残留网络中,相应地更新边的容量 c f ( u , v ) c_f(u, v) cf(u,v),以反映流量的变化。
  5. 重复步骤:返回步骤2,继续在更新后的残留网络中寻找最短增广路径,直到找不到增广路径为止。
    Edmonds-karp

三、Edmonds-Karp算法的代码实现

3.1 Python实现

from collections import dequedef edmonds_karp(graph, source, sink):rows = len(graph)residual_graph = [[graph[i][j] for j in range(rows)] for i in range(rows)]parent = [-1] * rowsmax_flow = 0while True:queue = deque()queue.append(source)visited = [False] * rowsvisited[source] = Truewhile queue:u = queue.popleft()for ind, val in enumerate(residual_graph[u]):if not visited[ind] and val > 0:queue.append(ind)visited[ind] = Trueparent[ind] = uif not visited[sink]:breakpath_flow = float("Inf")s = sinkwhile s != source:path_flow = min(path_flow, residual_graph[parent[s]][s])s = parent[s]max_flow += path_flowv = sinkwhile v != source:u = parent[v]residual_graph[u][v] -= path_flowresidual_graph[v][u] += path_flowv = parent[v]return max_flow# 示例图
graph = [[0, 16, 13, 0, 0, 0],[0, 0, 10, 12, 0, 0],[0, 4, 0, 0, 14, 0],[0, 0, 9, 0, 0, 20],[0, 0, 0, 7, 0, 4],[0, 0, 0, 0, 0, 0]
]
source = 0
sink = 5
print(edmonds_karp(graph, source, sink))

上述Python代码中,edmonds_karp 函数实现了Edmonds-Karp算法。首先初始化残留网络和记录前驱顶点的数组,然后通过一个无限循环不断使用BFS寻找增广路径。找到增广路径后,计算可增加的流量并更新流量和残留网络,直到找不到增广路径,最终返回最大流。

3.2 C++实现

#include <iostream>
#include <vector>
#include <queue>
using namespace std;bool bfs(vector<vector<int>>& residual_graph, int source, int sink, vector<int>& parent) {vector<bool> visited(residual_graph.size(), false);queue<int> q;q.push(source);visited[source] = true;while (!q.empty()) {int u = q.front();q.pop();for (int ind = 0; ind < residual_graph.size(); ind++) {if (!visited[ind] && residual_graph[u][ind] > 0) {q.push(ind);visited[ind] = true;parent[ind] = u;}}}return visited[sink];
}int edmonds_karp(vector<vector<int>>& graph, int source, int sink) {int n = graph.size();vector<vector<int>> residual_graph = graph;vector<int> parent(n);int max_flow = 0;while (bfs(residual_graph, source, sink, parent)) {int path_flow = INT_MAX;int v = sink;while (v != source) {path_flow = min(path_flow, residual_graph[parent[v]][v]);v = parent[v];}max_flow += path_flow;v = sink;while (v != source) {int u = parent[v];residual_graph[u][v] -= path_flow;residual_graph[v][u] += path_flow;v = parent[v];}}return max_flow;
}int main() {vector<vector<int>> graph = {{0, 16, 13, 0, 0, 0},{0, 0, 10, 12, 0, 0},{0, 4, 0, 0, 14, 0},{0, 0, 9, 0, 0, 20},{0, 0, 0, 7, 0, 4},{0, 0, 0, 0, 0, 0}};int source = 0;int sink = 5;cout << edmonds_karp(graph, source, sink) << endl;return 0;
}

C++代码中,bfs 函数负责在残留网络中使用BFS寻找增广路径,并记录路径上的前驱顶点。edmonds_karp 函数实现了算法的整体流程,包括初始化、调用 bfs 寻找增广路径、计算流量并更新残留网络,直至找不到增广路径,最后返回最大流。

3.3 Java实现

import java.util.LinkedList;
import java.util.Queue;class EdmondsKarp {static boolean bfs(int[][] residualGraph, int source, int sink, int[] parent) {boolean[] visited = new boolean[residualGraph.length];Queue<Integer> queue = new LinkedList<>();queue.add(source);visited[source] = true;while (!queue.isEmpty()) {int u = queue.poll();for (int ind = 0; ind < residualGraph.length; ind++) {if (!visited[ind] && residualGraph[u][ind] > 0) {queue.add(ind);visited[ind] = true;parent[ind] = u;}}}return visited[sink];}static int edmondsKarp(int[][] graph, int source, int sink) {int n = graph.length;int[][] residualGraph = new int[n][n];for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {residualGraph[i][j] = graph[i][j];}}int[] parent = new int[n];int maxFlow = 0;while (bfs(residualGraph, source, sink, parent)) {int pathFlow = Integer.MAX_VALUE;int v = sink;while (v != source) {pathFlow = Math.min(pathFlow, residualGraph[parent[v]][v]);v = parent[v];}maxFlow += pathFlow;v = sink;while (v != source) {int u = parent[v];residualGraph[u][v] -= pathFlow;residualGraph[v][u] += pathFlow;v = parent[v];}}return maxFlow;}
}public class Main {public static void main(String[] args) {int[][] graph = {{0, 16, 13, 0, 0, 0},{0, 0, 10, 12, 0, 0},{0, 4, 0, 0, 14, 0},{0, 0, 9, 0, 0, 20},{0, 0, 0, 7, 0, 4},{0, 0, 0, 0, 0, 0}};int source = 0;int sink = 5;System.out.println(EdmondsKarp.edmondsKarp(graph, source, sink));}
}

Java代码中,bfs 方法用于在残留网络中通过BFS寻找增广路径,并记录前驱顶点。edmondsKarp 方法实现了Edmonds-Karp算法的完整逻辑,包括初始化残留网络、调用 bfs 寻找增广路径、更新流量和残留网络,直至无法找到增广路径,最终返回最大流。

四、Edmonds-Karp算法的时间复杂度与空间复杂度分析

4.1 时间复杂度

Edmonds-Karp算法的时间复杂度分析如下:

  • 每次使用BFS寻找最短增广路径的时间复杂度为 O ( V + E ) O(V + E) O(V+E),其中 V V V 是顶点数量, E E E 是边的数量。
  • 由于每次沿着最短增广路径增加流量后,至少会使某条边的流量达到其容量上限(即某条边在残留网络中消失或出现反向边),而边的数量为 E E E,所以增广路径的数量最多为 O ( V E ) O(VE) O(VE) 次。
  • 综合以上两点,Edmonds-Karp算法的时间复杂度为 O ( V E 2 ) O(VE^2) O(VE2)。相比Ford-Fulkerson算法在最坏情况下的时间复杂度 O ( ∣ f ∗ ∣ ( V + E ) ) O(|f^*|(V + E)) O(f(V+E)) ∣ f ∗ ∣ |f^*| f 为最大流的值),Edmonds-Karp算法通过选择最短增广路径,保证了更优的时间复杂度,使其在大多数情况下具有更好的性能表现。

4.2 空间复杂度

Edmonds-Karp算法的空间复杂度主要取决于存储网络和残留网络以及辅助数据结构所需的空间:

  • 存储网络和残留网络:如果使用邻接矩阵存储,空间复杂度为 O ( V 2 ) O(V^2) O(V2);若使用邻接表存储,空间复杂度为 O ( V + E ) O(V + E) O(V+E)。通常在实际应用中,邻接表更适合存储稀疏图,空间效率更高。
  • 辅助数据结构:算法在执行过程中,需要使用队列存储BFS搜索过程中的顶点,以及数组(或列表)记录增广路径上的前驱顶点等辅助数据。队列在最坏情况下可能存储所有顶点,空间复杂度为 O ( V ) O(V) O(V);记录前驱顶点的数组空间复杂度也为 O ( V ) O(V) O(V)。因此,辅助数据结构的空间复杂度为 O ( V ) O(V) O(V)
  • 综合起来,在使用邻接表存储网络时,Edmonds-Karp算法的空间复杂度为 O ( V + E ) O(V + E) O(V+E)

五、Edmonds-Karp算法的应用场景

5.1 资源分配

在资源分配场景中,如工厂生产资源分配、云计算资源分配等,可将资源的生产者视为源点,资源的消费者视为汇点,资源的传输路径视为边,边的容量表示路径能够传输的资源量上限。通过Edmonds-Karp算法可以找到一种最优的资源分配方案,使得从生产者到消费者的资源传输总量最大,从而实现资源的高效利用和合理分配。

5.2 网络通信

在计算机网络通信中,数据从源节点传输到目标节点,网络中的链路可看作边,链路的带宽可看作边的容量。利用Edmonds-Karp算法能够计算出在给定网络拓扑和链路带宽的情况下,从源节点到目标节点的最大数据传输量。这有助于网络管理员优化网络拓扑结构、合理分配带宽资源,提高网络的传输效率和稳定性,避免网络拥塞。

5.3 交通运输

在城市交通系统中,道路可视为边,道路的通行能力可视为边的容量,城市中的某些关键地点(如交通枢纽)可作为源点和汇点。以北京为例,将国贸、西直门等交通枢纽设为源点,将郊区物流中心设为汇点,通过 Edmonds-Karp 算法分析城市交通网络的最大通行流量,能够为交通规划提供重要依据。具体而言,算法可通过识别网络中的 “瓶颈路段”,即限制整体流量的关键道路,为交通规划提供关键决策支持:例如确定需要拓宽哪些路段来提升整体通行效率;规划地铁、高架桥等新交通设施的最佳建设位置,以分担现有道路的压力;甚至可以优化信号灯配时方案,让道路资源得到更高效的利用。此外,通过动态调整源点和汇点,算法还能模拟不同区域在高峰时段的流量变化,帮助制定更科学的潮汐车道管理策略。

总结​

作为网络流问题的经典算法,Edmonds-Karp 基于广度优先搜索(BFS)策略寻找最短增广路径,相比传统 Ford-Fulkerson 方法,在时间复杂度上实现了显著优化。

That’s all, thanks for reading!
觉得有用就点个赞、收进收藏夹吧!关注我,获取更多干货~


http://www.hkcw.cn/article/LOigEUpGVC.shtml

相关文章

软件设计综合知识

software-design 软考中级-软件设计师-综合知识&#xff1a;计算机系统基础、操作系统、计算机网络与信息安全、程序语言基础、数据库基础、数据结构与算法、软件工程基础知识、标准与知识产权等。 —— 2025 年 3 月 5 日 甲辰年二月初六 惊蛰 目录 software-design1、计算机基…

(一)微服务(垂直AP/分布式缓存/装饰器Pattern)

文章目录 项目地址一、创建第一个垂直API1.1 创建Common层1. ICommand接口2. IQuery接口 1.2 创建API1. 实体2. Handler3. endpoint 1.3 使用Marten作为ORM 二、Redis缓存2.1 使用缓存装饰器1. 创建装饰器2. 注册装饰器 2.2 创建docker-compose1. docker-compose2. docker-comp…

单依纯疑似回应演唱失误 沉浸演绎引共鸣

在歌手第三期的袭榜赛中,单依纯获得了第二名。一些网友对此表示惊讶,认为她连续两期夺冠后,这次居然输给了断眉,只拿到第二名。不过大多数网友认为直播中的失误是正常现象。单依纯在微博上回应了此事,她表示《爱情》这首歌很早就在她的备选歌单里,《Yesterday Once More》…

汽车被巨石砸中司机逃生 当地回应 地质灾害点已设警示牌

5月28日,贵州毕节市七星关区何官屯镇的一条通村公路上发生了一起突发落石事件。一块约300斤重的巨石砸中一辆过路汽车,导致车辆从路边高坎坠落。司机受轻伤,送医检查后当日返家,车损由保险公司处理。落石还击碎了附近民房的玻璃门,但没有造成人员受伤。当地多部门表示,事…

警方:进入兵马俑坑男子患精神疾病 警情通报发布

5月31日03时15分,平安临潼通过新浪微博发布了一则警情通报。责任编辑:zhangxiaohua

激光武器是否会重塑现代战争形态 以色列首次战场应用引发讨论

当地时间28日,以色列国防部宣布,在针对巴勒斯坦伊斯兰抵抗运动(哈马斯)的军事行动中,以军使用激光武器进行了数十次拦截。这是以色列首次承认在战场上使用激光武器,引发外界广泛关注。以色列国防部长卡茨认为这一技术将改变该地区的游戏规则。以色列公布了一段激光武器拦…

今夏首签!官方:利物浦签24岁荷兰边卫弗林蓬,付3500万解约金 五年长约锁定未来

利物浦宣布签下勒沃库森右边翼卫弗林蓬。据报道,红军支付了3500万欧元的解约金,双方签约五年。弗林蓬出生于荷兰,拥有加纳血统,7岁时随家人移居英国,并在9岁时加入曼城梯队。他在曼城各级梯队成长,2019年离开曼城,以38万欧元的转会费加盟凯尔特人。2021年冬窗,勒沃库森…

端午节北京云量较多 白天阴有阵雨最高气温28℃ 假期出行需带雨具

今天是端午节,北京云量较多,白天阴有阵雨,最高气温28℃。假期后两天,北京云量依然较多,可能会有雷雨,公众外出需带好雨具,小心慢行,注意交通安全。昨天,北京以晴天为主,最高气温达到29.2℃,午后出行体感微热。今晨,北京天空阴沉,海淀、门头沟等多地出现降雨。端午…

世俱杯夺冠赔率:皇马居首曼城拜仁三甲 2025赛事即将揭幕

2025年世俱杯将于6月15日拉开帷幕,目前皇马被认为是夺冠的最大热门。曼城以5.5的赔率紧随其后,拜仁则以7的赔率位列第三。利雅得新月和迈阿密国际的夺冠赔率均为67,并列第18位。以下是世俱杯夺冠赔率前十名的具体情况: - 皇马:4.5 - 曼城:5.5 - 拜仁:7 - 巴黎圣日耳曼:…

“车圈恒大”到底存不存在 中国车企财务更稳健

汽车产业中的高负债问题引发激烈讨论,有人将某些车企比作“车圈恒大”,但这种类比忽略了汽车与房地产的本质差异。车企的负债主要用于研发和生产投资,而非高杠杆囤地,因此资产流动性和现金流稳定性远超房企。比亚迪集团品牌及公关处总经理李云飞通过个人微博回应了这一观点…

玉渊谭天丨签证限制升级背后:美国的困局

当地时间5月28日,美国国务院发布公告称,将开始大力撤销中国留学生的签证。美国政府近年来多次在中国留学生签证的问题上使绊子,总结起来,大致分为四类:将大学和研究机构列入实体清单;签证管控;限制中美正常交流项目;对研究人员采取持续调查。这一次,主要聚焦在签证管控…

Transformer 通关秘籍11:Word2Vec 及工具的使用

将文字文本转换为词向量(word embedding&#xff09;的过程中&#xff0c;一个非常著名的算法模型应该就是 Word2Vec 了。 相信大家或多或少都听说过&#xff0c;本节就来简单介绍一下 Word2Vec 。 什么是 Word2Vec &#xff1f; Word2Vec 可以非常有效的创建词嵌入向量&…

数组做函数参数,嵌套调用与链式访问

文章目录 前言一、数组做函数参数二、嵌套调用和链式访问2.1 嵌套调用2.2 链式访问 前言 这一块内容是衔接上一节函数内容&#xff0c;从更层次分析函数之中的细节 一、数组做函数参数 在平时用函数解决问题的时候&#xff0c;难免会将数组作为参数传递给函数&#xff0c;在函…

央行降息 普通人该做什么 调整投资组合应对变化

2025年5月7日,央行宣布实施“双降”政策,“降准0.5%+ 降息0.1%”,释放长期流动性约1.2万亿元。这是继2024年9月后又一次超预期的货币政策调整。此次政策的核心目标是降低实体经济融资成本,刺激居民消费,稳定楼市,实现经济“软着陆”。“双降”政策对投资者会产生影响。主…

北京多区居民被巨响惊醒 系火流星 夜空奇观点亮京城

2025年5月31日凌晨2时51分,一颗火流星划过北京夜空。凌晨3时左右,北京通州、顺义、怀柔等多区居民在睡梦中被一声巨响惊醒,少数居民目击了漆黑夜空被“点亮”的奇观。中国科学院大学流星多站视频监测网的兴隆流星观测站成功捕捉到这次天文现象,记录下明亮的火流星照亮北京夜…

油价要涨!5月31日92号汽油价格 预计下周上调

今日最新油价调整资讯显示,5月31日的油价预计将在6月3日晚进行调整,上调幅度约为80元/吨(0.05元/升-0.07元/升)。这意味着刚刚在5月大幅下跌的油价将重新上涨。截至5月31日0时,国际原油市场的最新情况是纽约商品交易所(WTI)原油价格下跌0.44%,每桶报价60.67美元;布伦特原…

美的集团董事长方洪波再谈小米 战略上不惧竞争

5月30日下午,美的集团在佛山总部召开2024年度股东大会。今年小米在空调市场掀起低价竞争,其大家电业务一季度收入同比翻倍增长。此前,方洪波在访谈中提到“在战术上重视小米、在战略上不惧怕小米”。有投资者在美的股东大会上追问这句话的含义。方洪波解释说,家电业是高度竞…

龙舟赛上划最快的原来是救援队 去年也是他们最快

端午佳节,山东济南大明湖景区举行了一场盛大的龙舟赛,吸引了众多游客前来观赛。上午9时39分许,两只龙舟敲鼓出发进行比拼。然而比赛刚开始不久,围观人群中就传来呼声,一艘龙舟翻船了。现场目击者称,刚一开始,比赛就结束了。翻船的是落后的那只龙舟,但船员们都穿着救生衣…

古画里的端午氛围感拉满 解锁千年仪式感

端午节作为中国四大传统节日之一,在2000余年的历史长河中积累了丰富的仪式感。端午节前夕,山东博物馆通过古画和年画展示了多样的节俗。在文物鉴赏室,山东博物馆书画部研究馆员鲍艳囡展示了清朝大臣蒋溥所绘的《天中五瑞图》。这幅1米多长的画轴上,蜀葵、菖蒲、石榴花、枇杷…

“车圈恒大论”之下汽车行业谁最焦虑 负债真相解析

长城汽车董事长魏建军近期关于“汽车行业‘恒大’已经出现,只不过没爆”的言论引起了广泛关注。这一观点不仅揭示了新能源转型过程中部分企业的焦虑,也引发了对车企资产负债结构和盈利能力的深入讨论。将汽车行业简单类比为房地产行业的高杠杆模式并不准确。作为技术密集型制…