老城区的地下水管网已经用了三十年。水库 S 在城东,新建的蓄水池 T 在城西,中间是织满大街小巷的管道网。每一段管道都有直径限制,水只能沿固定方向前进;老检修工王师傅的任务,是在雨季前算清楚一天最多能往蓄水池送多少水。这听起来是个水管问题,但它其实是一类数学模型的化身——网络流。把管道换成有容量的边,把阀门换成节点,把“最多能送多少水”换成最大流,就是我们要解的题。EK(Edmonds-Karp)和 Dinic 是两套经典解法:EK 像维修队每次走“管子数量最少”的路线送水,Dinic 像先给整张管网画好海拔分层再一口气灌满所有可用通道。理解它们,你不仅能算出最大流,还能看清许多调度、分配、匹配问题的本质。

岗位关联

对 AI 从业者而言,网络流是任务分配、资源调度、图匹配等组合优化问题的“最强大脑”;看懂 EK 与 Dinic,你就知道在数据规模变大时该用哪把扳手,也更容易理解编译器、分布式系统中那些隐藏的最优化决策。

目录
  1. 可视化演示
  2. 网络流基础
  3. 残留网络
  4. 增广思想
  5. EK算法
  6. Dinic算法
  7. 单位网络
  8. 对比应用
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

网络流算法用于求解最大流问题,Edmonds-Karp基于BFS增广路复杂度为O(VE^2),Dinic利用分... 切换模式查看不同维度。

本节配有交互动效(进入视口后自动加载,约 3KB)。

最大流问题与:核心原理 动态展示关键流程与数据流动 交互控件调节参数实时渲染 f(x) = transform(x) 核心概念的可视化呈现

网络流基础

王师傅拿到管网图后,第一件事不是急着开闸,而是给每个中间阀门贴一张规则牌:“进来的水必须等于出去的水,一滴都不能囤。”水库能供水,蓄水池能接收,中间节点只是透明的分流站。这个朴素的生活规则,正是网络流最核心的骨架。

把地图抽象成数学对象:有向图 G=(V,E) 中的顶点是阀门,边是管道,容量 c(u,v) 是管道粗细,流量 f(u,v) 是实际送水量。除了源点 s 和汇点 t,任何中间节点都不能凭空产生或吞掉水。于是网络流问题就是在遵守下列规则的条件下,让从 s 到 t 的总流量最大。

回到地图上,王师傅把规则贴在墙上后,真正的工程才开始:他需要一套系统方法,反复寻找还能送水的路线,直到整个管网再也挤不出更多水。

0≤f(u,v)≤c(u,v),∑(u,v)∈Ef(u,v)=∑(v,w)∈Ef(v,w)(∀v≠s,t)\displaystyle 0 \le f(u,v) \le c(u,v), \qquad \sum_{(u,v)\in E} f(u,v) = \sum_{(v,w)\in E} f(v,w) \quad (\forall v\neq s,t)
这条公式像“交通规则”:每条路不能超载,每个路口不能堵车囤货。最大流就是在这两条规则下能送到终点的最多水量。
  1. 流量非负f(u,v) \ge 0:水不能倒灌,任何管道的实际流量不能为负数。
  2. 容量上界f(u,v) \le c(u,v):管道粗细决定了单条管线最多能通过多少水。
  3. 流量守恒\sum_{(u,v)\in E} f(u,v) = \sum_{(v,w)\in E} f(v,w):对每个中间节点,流入量必须恰好等于流出量,水既不能积压也不能凭空出现。
  4. 最大流目标\max |f|:在所有可行方案中,选择从源点送到汇点总水量最大的那个。

残留网络

老王每送完一轮水,都会在图纸上用两种颜色做记录:红色标出“这根管道还能加多少”,蓝色标出“之前送的量能不能退回来”。这张记录当前所有“可操作空间”的动态图纸,就是残留网络。

技术上说,如果边 (u,v) 已经流了 f(u,v),那么在残留网络 G_f 中,正向边还剩下 c_f(u,v)=c(u,v)-f(u,v) 的容量;同时要添加一条反向边 c_f(v,u)=f(u,v),它不代表物理倒流的管道,而是“撤销额度”——允许我们退回之前错误分配的水。没有反向边,很多一开始选错路线的方案就永远无法修正。

老王把红色和蓝色标满整张图后,找路就变成了看“哪里有连续的红色或蓝色箭头能从 S 连到 T”。这张动态图纸,是所有增广路算法的舞台。

cf(u,v)=c(u,v)−f(u,v),cf(v,u)=f(u,v)\displaystyle c_f(u,v)=c(u,v)-f(u,v), \qquad c_f(v,u)=f(u,v)
残留网络像一张“水位报表”:正向数字代表还能灌多少,反向数字代表能退多少。只要报表上还有从源到汇的路,就说明流量还能继续涨。
  1. 正向余量c_f(u,v)=c(u,v)-f(u,v):管道还没用满的部分,是未来还能增加的流量空间。
  2. 反向余量c_f(v,u)=f(u,v):已经送出的流量可以被撤销的上限,等价于把之前某一步的决策改回去。
  3. 可增广路P: s \rightsquigarrow t:在残留网络中存在从源点到汇点的路径时,当前流就还没有达到最大。
  4. 路径容量P 上所有边的 c_f 都为正值:这条路才真正“走得通”。

增广思想

既然残留网络里已经画出了所有“还能走的路”,接下来就简单了:每次找到一条从 S 到 T 的可增广路,把这条路上最窄管道的剩余容量作为增量 δ 加上去。为什么要取最小值?因为一条管线的输送能力由最细的一段决定,这就是瓶颈。

一轮增广之后,残留网络会立刻变化:正向边被用掉一些,反向边被记下新账。于是再找下一条路,再增广,直到整个残留网络里再也找不到从 S 到 T 的路径。此时由增广路定理与最大流最小割定理可知,当前流量已经达到最大值——不是“暂时找不到路”,而是任何继续增加流量的方案都会被某个最小割的管道瓶颈挡住。

王师傅发现,这个“找路—加量—再看图”的思路谁都能听懂,但如何找路、找多少次,直接决定了效率。于是他准备了两套施工方案。

δ=min⁡(u,v)∈Pcf(u,v),f′(u,v)=f(u,v)+δ, (u,v)∈E;f′(u,v)=f(u,v)−δ, (v,u)∈E.\displaystyle \delta=\min_{(u,v)\in P} c_f(u,v), \qquad f'(u,v)=f(u,v)+\delta,\ (u,v)\in E; \qquad f'(u,v)=f(u,v)-\delta,\ (v,u)\in E.
增广就像给一条水管线路“加压”:加多少由最细的管道决定;增广完立刻盘点还有没有其他能加压的路线;直到所有路线都紧到极限,就是最大流。
  1. 瓶颈增量\delta=\min_{(u,v)\in P} c_f(u,v):整条增广路的可加水量等于所有残留容量中的最小值。
  2. 正向加流f'(u,v)=f(u,v)+\delta:沿原始管道方向增加流量,记入新的实际送水量。
  3. 反向减流f'(u,v)=f(u,v)-\delta:若路过反向边,则等价于撤销之前的一部分流量,而不是物理倒水。
  4. 终止判定残留网络中不存在从 s 到 t 的路径:当前方案已经是最大流,继续寻找不会再有任何收益。

EK算法

王师傅的第一套方案很笨但可靠:每次从水库出发,用 BFS 按“经过的管道根数最少”找一条到蓄水池的路线。为什么必须是最短路线?因为如果任选一条可行路就送水,可能绕来绕去浪费大量轮次;而 BFS 保证每轮增广后,源点到汇点的最短距离单调不减,整体增广次数被压缩到 O(VE) 以内。

EK 算法实现起来几乎是直觉的:维护一个残留容量矩阵,每次 BFS 找增广路并记录前驱,然后沿路径找到瓶颈增量,再正向减、反向加地更新残留网络。当 BFS 再也到不了汇点时,算法结束。它的最坏时间复杂度是每次 BFS 的 O(E) 乘以最多 O(VE) 次增广。

老王的体会是:EK 像“宁可多跑几趟也要保证每趟都是最短路线”,适合管道不多的小片区;一旦整张地图变得密密麻麻,就该换第二套方案。

TEK=O(E)×O(VE)=O(VE2)\displaystyle T_{\text{EK}} = O(E) \times O(VE) = O(VE^2)
EK 的复杂度像“每次按最短路线跑一趟,最多跑 V×E 趟”,所以最终代价是 E 的平方。对小网络来说足够,边数一多就会明显吃力。
  1. 单次 BFS 成本O(E):在残留网络里用队列扩展所有可达顶点,需要扫描全部边。
  2. 增广次数上界O(VE):每轮至少让一条关键边的残留容量降为 0,而路径长度变化受顶点数限制。
  3. 总复杂度O(VE^2):把每一轮 BFS 的代价与轮数相乘,得到最坏运行时间。
  4. 空间复杂度O(E):只需要保存残留容量矩阵和 BFS 的前驱数组。

Dinic算法

第二种方案高级得多:先用 BFS 给整个管网画海拔线——从源点出发,算出每个节点到源点的最短距离,这就是分层图;然后规定水只能从低层流向高一层,绝不走回头路。在这个有向无环的层次结构里,用 DFS 一次找出所有能走的路,直到无法向更高层推进,形成一轮阻塞流。之后重新画海拔线,再来下一轮。

Dinic 的核心优势是把“找一条路”升级成“一次找一批路”。每轮 BFS 建图成本是 O(E),一轮 DFS 找阻塞流在当前弧优化下是 O(VE);而层次图每轮都会让最短路径至少增加 1,所以阶段数不超过 O(V)。由此得到最坏复杂度:

对老王来说,Dinic 就像看了整体地形才动手:先分层,再批量送水,明显比 EK 一趟趟跑更省时间。而在一种特殊地形里,Dinic 的优势还会被进一步放大。

TDinic=O(V)×O(VE)=O(V2E)\displaystyle T_{\text{Dinic}} = O(V) \times O(VE) = O(V^2E)
Dinic 像老王先给整条街画好“海拔等高线”,再一口气把所有能从低处流向高处的通道全部灌满。虽然单轮工作变重,但总轮数大幅减少。
  1. 建层次图O(E):一次 BFS 就能给所有顶点标出到源点的最短距离层号。
  2. 找阻塞流O(VE):DFS 沿着层号严格递增的方向多路搜索,当前弧优化保证每条边每阶段最多被检查一次。
  3. 阶段数上界O(V):每完成一个阶段,源点到汇点的最短距离至少增加 1,最多增加到 V-1。
  4. 总复杂度O(V^2E):阶段数乘以每阶段成本,得到最坏情况下的时间上界。

单位网络

如果整张管网里每根管道都一样粗,并且容量恰好为 1,问题就变成单位网络。最典型的场景是二分图最大匹配:源点连左部顶点、右部顶点连汇点,容量全为 1;左部到右部的匹配边也设容量 1。每一单位流量都代表一个配对,最大流就是最大匹配数。

单位容量带来一个特殊红利:每条增广路只能携带 1 单位流量,且层次图中每条路径都很“窄”。于是阶段数的理论上界从一般网络的 O(V) 收紧到 O(\sqrt V),每阶段仍为 O(E),总复杂度变成:

正因为单位网络有如此漂亮的复杂度,二分图匹配、任务分配这类“一对一”问题在工程中都愿意建模成网络流,再交给 Dinic 求解。

TDinic(unit)=O(EV)\displaystyle T_{\text{Dinic(unit)}} = O(E\sqrt{V})
单位网络就像“每根水管只送一桶水”的配对游戏:管道规则简单,博弈路径也短,Dinic 能以接近线性的速度扫清战场。
  1. 单位容量限制f(e)\in\{0,1\}:每条边要么空着,要么被一单位流量占满,单次增广增量恒为 1。
  2. 阶段数上界O(\sqrt V):前 √V 个阶段后,残留增广路必须变得足够长,路径条数受剩余顶点数限制。
  3. 每阶段成本O(E):单位网络的 BFS 与 DFS 依然只需扫描一遍边。
  4. 总复杂度O(E\sqrt V):每阶段 O(E),阶段数 O(\sqrt V),两者相乘。

对比应用

两套方案到底怎么选?老王总结出一条经验:看地形。边数很少的稀疏管网,EK 写起来简单、验证快,虽然理论复杂度不高,但常数小;边数多、顶点多的稠密网络,Dinic 的分层灌水法明显更占优,尤其是单位网络场景,Dinic 能把复杂度压到 O(E√V),几乎是一般网络的特快通道。

把两个复杂度放在一起看:

老王最终把两把扳手都放进了工具箱:遇到复杂地形,先建模,再根据图的形态选择算法。看懂这两套方案,你也就掌握了网络流从理论到工程落地的完整地图。

TEK=O(VE2),TDinic=O(V2E)\displaystyle T_{\text{EK}}=O(VE^2), \qquad T_{\text{Dinic}}=O(V^2E)
EK 被边的平方拖累,Dinic 被顶点的平方拖累。稀疏时两者接近,稠密时 Dinic 更值得信赖;若再叠加单位容量,Dinic 基本就是最优选择。
  1. EK 的瓶颈O(VE^2):边越多,BFS 的轮数和每轮的扫描成本同时上升,平方项来自 E。
  2. Dinic 的瓶颈O(V^2E):最坏阶段的次数由顶点数 V 主导,边数只以一次方出现。
  3. 稀疏图选 EKE\approx V:两者量级相近,EK 实现更直接,适合快速原型。
  4. 稠密/单位图选 DinicE\sqrt V 远小于 VE^2:网络越密、容量越规整,Dinic 优势越明显。

AI 应用场景

云平台任务调度

阶段:数据/算力资源调度

解决的问题:传统的贪心调度容易陷入局部最优,导致某些 GPU 空闲、某些任务排队。把“任务—GPU 可运行关系”建模成二分图,用单位网络上的 Dinic 求最大匹配,可以一次性得到最多能同时执行多少个任务。

具体案例:一个推理平台有 1000 个预处理任务和 800 个 GPU 实例,每个任务只能在部分 GPU 上运行。把源点连任务、任务连可用 GPU、GPU 连汇点,容量全为 1,跑一遍 Dinic 就能得到最大并行分配数,并快速定位哪些任务无法被满足。

数据中心流量调度

阶段:训练集群带宽分配

解决的问题:大模型分布式训练时,多张显卡需要同步梯度,主链路经常成为瓶颈。把机房链路抽象成流网络,用最大流算法计算从参数服务器到工作节点的最大可用带宽,能清晰看出哪些链路需要扩容。

具体案例:在某 BERT 预训练任务中,64 张卡同步梯度时总带宽不足。工程师将交换机的每根链路设成带容量边,用 EK 快速验证小规模拓扑,再用 Dinic 在完整拓扑上找到瓶颈割,最终通过调整通信拓扑让一轮同步时间缩短 30%。

编译器寄存器分配

阶段:编译优化与后端代码生成

解决的问题:编译器要把大量活跃变量映射到有限寄存器上,本质是一个匹配问题。把“变量生命周期”和“寄存器槽位”建模成二分图,用单位网络最大流估算最多能同时放入寄存器的变量数,能帮助决定何时触发寄存器溢出。

具体案例:在 LLVM 后端的寄存器压力分析中,某个热循环有 40 个活跃变量但只有 16 个可用寄存器。通过二分图最大匹配先算出可驻留寄存器的上限,再配合启发式染色,显著减少了内存加载指令。

Python 演示

python83 行
from collections import deque def edmonds_karp(cap, s, t):    n = len(cap)    flow = 0    while True:        prev = [-1] * n        prev[s] = s        q = deque([s])        while q and prev[t] == -1:            u = q.popleft()            for v in range(n):                if cap[u][v] > 0 and prev[v] == -1:                    prev[v] = u                    q.append(v)        if prev[t] == -1:            return flow        add = 10 ** 9        v = t        while v != s:            u = prev[v]            add = min(add, cap[u][v])            v = u        v = t        while v != s:            u = prev[v]            cap[u][v] -= add            cap[v][u] += add            v = u        flow += add def dinic(edges, n, s, t):    graph = [[] for _ in range(n)]    def add_edge(u, v, c):        graph[u].append([v, c, len(graph[v])])        graph[v].append([u, 0, len(graph[u]) - 1])    for u, v, c in edges:        add_edge(u, v, c)    level = [-1] * n    it = [0] * n    def bfs():        for i in range(n):            level[i] = -1        q = deque([s])        level[s] = 0        while q:            u = q.popleft()            for v, c, r in graph[u]:                if c > 0 and level[v] < 0:                    level[v] = level[u] + 1                    q.append(v)        return level[t] >= 0    def dfs(u, f):        if u == t:            return f        while it[u] < len(graph[u]):            e = graph[u][it[u]]            v, c, r = e            if c > 0 and level[v] == level[u] + 1:                ret = dfs(v, min(f, c))                if ret:                    e[1] -= ret                    graph[v][r][1] += ret                    return ret            it[u] += 1        return 0    ans = 0    while bfs():        it = [0] * n        while True:            f = dfs(s, 10 ** 9)            if not f:                break            ans += f    return ans if __name__ == '__main__':    edges = [(0, 1, 10), (0, 2, 5), (1, 3, 8), (2, 3, 5)]    cap = [[0] * 4 for _ in range(4)]    for u, v, c in edges:        cap[u][v] += c    print('EK   :', edmonds_karp(cap, 0, 3))    print('Dinic:', dinic(edges, 4, 0, 3))
目的:在同一张网络上分别实现 EK 与 Dinic,并输出最大流验证结果,帮助理解两个算法的等价目标与不同实现路径。
  1. if cap[u][v] > 0 and prev[v] == -1:BFS 只在仍有剩余容量且顶点未访问时才前进,这正是残留网络上的可增广路搜索。
  2. add = min(add, cap[u][v])沿路径找出最小值,对应“最细管道决定整条路能送多少水”的瓶颈思想。
  3. cap[u][v] -= add正向边减去本次增广量,更新残留容量。
  4. cap[v][u] += add反向边加上同样的量,记录未来可以撤销的额度。
  5. graph[u].append([v, c, len(graph[v])])存储正向边的同时记下反向边在邻接表中的位置,方便 O(1) 更新。
  6. if c > 0 and level[v] == level[u] + 1:DFS 只沿层次图逐级前进,保证水始终从低层流向高一层。
  7. it[u] += 1当前弧优化:这条边已经饱和或无效,下一阶段直接跳过,避免重复检查。
  8. while bfs():每成功建一次层次图,就开启 Dinic 的一个新阶段。
  9. f = dfs(s, 10 ** 9)从源点发起多路阻塞流搜索,一次返回一条增广增量。
  10. print('EK :', edmonds_karp(cap, 0, 3))在小图上对比两种算法的输出,验证它们得到相同最大流。

常见误区

误区残留网络里的反向边代表水真的可以倒流回去,所以实际工程中要实现双向管道。

正解反向边只是算法层面的“撤销额度”,表示我们可以退回之前分配的流量,从而修正早期错误决策。物理上水流方向始终由原始有向边决定。就像送水单可以改签,但不代表已经送出去的水会倒流回家。

为何常见:残留网络画出来和原图一样是有向箭头,初学者很容易把“虚拟记账”误认为“物理管道”。

误区既然是找一条可行路径,用 BFS 还是 DFS 没区别,反正都能到达汇点。

正解EK 的复杂度保证完全依赖 BFS 找到的“最短(边数最少)增广路”。如果改用 DFS 随意找,最坏情况下增广次数可能变成指数级,算法会彻底退化。就像维修队不按最短路线走,绕路次数会失控。

为何常见:小图上 DFS 往往是“能到达汇点”的,于是让人误以为路径选择无所谓。

误区分层图建好之后,DFS 每次递归都要重新检查所有邻接边,反正图不大。

正解Dinic 必须配合当前弧优化:每个顶点的边指针只前进不后退,已经饱和或无法推进的边在本阶段不再检查。没有这个优化,阻塞流搜索会退化成大量重复扫描,复杂度失去保证。

为何常见:初学者只关注“分层”这个直观概念,忽略了“当前弧”才是让每边只处理一次的关键工程细节。

误区水库出口的管道容量加起来是多少,最大流就应该是多少。

正解源点出边容量只是上界之一,整个网络还可能被中间管道或汇入汇点的边卡住。最大流等于最小割容量,割可以出现在任意位置。就像水库出口再粗,通往城西的主水管不够粗,水照样送不过去。

为何常见:看到源点出边最多就以为瓶颈只在源头,忽略了网络中“最窄处”往往藏在中间。

面试题

Q1. 在流网络中,除源点和汇点外,任意中间节点必须满足什么条件?

单选题 · easy

  • A.流入量大于流出量
  • B.流入量等于流出量← 正确答案
  • C.流入量小于流出量
  • D.无需任何限制

答案:B。中间节点不能囤水也不能凭空产水,流入必须等于流出。这对应“流量守恒”,就像阀门只是分流站,不存水。A、C 都会造成水堆积或消失,D 则完全违背规则。

Q2. 残留网络中的反向边容量表示什么?

单选题 · easy

  • A.原来管道能承受的最大额外流量
  • B.已经沿正向边输送的流量,也就是可以撤销的量← 正确答案
  • C.从汇点流向源点的实际流量
  • D.未被使用的正向容量

答案:B。反向边容量等于当前已发送流量 f(u,v),代表我们可以退回多少水。它不是真实物理管道,而是算法里的“改签额度”。A 是正向剩余容量,D 也是正向概念,C 是错误理解。

Q3. 最大流最小割定理说明什么?

单选题 · easy

  • A.最大流等于最小割容量← 正确答案
  • B.最大流等于所有边容量之和
  • C.最小割等于源点出边之和
  • D.最大流与割无关

答案:A。定理核心是最大流值恰好等于一个最小割的容量。也就是说,网络的最大输送能力被某个最窄的“切口”完全决定,而不是所有边容量之和。

Q4. EK 算法为什么必须用 BFS 找增广路?

单选题 · mid

  • A.BFS 一定能找到容量最大的路径
  • B.BFS 能找到边数最少的增广路,保证增广次数为 O(VE)← 正确答案
  • C.BFS 能避免使用反向边
  • D.BFS 可以在 O(1) 内完成

答案:B。EK 的复杂度证明依赖“每次找最短增广路”这一性质,它让残留网络中源汇最短距离单调增加,从而限制增广轮数。BFS 正好保证这一点,DFS 则没有这个理论保证。

Q5. Dinic 算法中“当前弧优化”主要解决什么问题?

单选题 · mid

  • A.减少 BFS 层次图的构建次数
  • B.避免 DFS 反复检查已经饱和或无效的边← 正确答案
  • C.保证残留网络中没有反向边
  • D.让源点的出边永远优先被选择

答案:B。当前弧优化让每个顶点的边指针只前进不后退,已经榨干或无法增广的边在同一阶段不再检查。它不改变 BFS 次数,也不消除反向边,而是加速阻塞流搜索。

Q6. 在把二分图最大匹配建模为网络流时,连接源点到左侧顶点的边容量通常设为?

单选题 · mid

  • A.该顶点的度数
  • B.1← 正确答案
  • C.所有边容量之和
  • D.无穷大

答案:B。单位网络里每个左部顶点最多匹配一次,所以源点到左部的边容量为 1。右部到汇点同样为 1。这保证一条流量最多对应一个配对。

Q7. 单位容量网络上 Dinic 的时间复杂度是?

单选题 · mid

  • A.O(VE)
  • B.O(V^2 E)
  • C.O(E√V)← 正确答案
  • D.O(V^3)

答案:C。单位容量让每条增广路最多携带 1 单位流量,阶段数从 O(V) 收紧到 O(√V),每阶段 O(E),因此总复杂度为 O(E√V)。这也是二分图匹配中 Dinic 高效的原因。

Q8. 一个有 V 个顶点、E 条边的流网络,EK 算法的最坏时间复杂度是?

单选题 · hard

  • A.O(VE)
  • B.O(V^2 E)
  • C.O(VE^2)← 正确答案
  • D.O(E^2)

答案:C。EK 的每轮 BFS 是 O(E),而增广轮数上界是 O(VE),两者相乘得到 O(VE^2)。边数越稠密,EK 越吃亏,这也是工程中常选 Dinic 的原因。

Q9. 下列关于 Dinic 算法步骤的描述,正确的有哪些?

多选题 · hard

  • A.用 BFS 构建从源点到各顶点的分层图← 正确答案
  • B.DFS 在分层图中反复寻找阻塞流← 正确答案
  • C.一个阶段只允许增广一条路径
  • D.当前弧优化可加速阻塞流搜索← 正确答案

答案:ABD。Dinic 先用 BFS 分层,再用 DFS 一次找多条路径直到形成阻塞流,所以一个阶段会增广多条路径,C 错误。当前弧优化避免重复扫描边,确实是关键加速手段。

Q10. 为什么 Dinic 在单位网络中的复杂度优于一般网络?

单选题 · extreme

  • A.单位网络中所有边容量都是 1,阻塞流每次增广的增量恒为 1
  • B.单位网络的层次图深度最多为 2
  • C.单位网络中每条边都被看作残留网络的正向边,没有反向边
  • D.阶段数理论上界从 O(V) 降到 O(√V),总复杂度成为 O(E√V)← 正确答案

答案:D。A 说的是单位容量带来的表面现象,但真正让复杂度变优的是阶段数上界从 O(V) 收紧到 O(√V),再乘每阶段 O(E),得到 O(E√V)。B 和 C 都对单位网络理解错误。