图与网路——最大流问题精解

news/2024/9/19 15:46:35/文章来源:https://www.cnblogs.com/haohai9309/p/18408632

容量网络(Capacity Network)是一种特殊的有向图结构,其中每条边都有一个容量(Capacity),表示该边上可以通过的最大流量。在这种网络中,流量(Flow)是指从源点(Source)通过边到达汇点(Sink)的实际传输量。容量网络中的边具有方向性,且每条边的流量不能超过其容量。最大流问题(Maximum Flow Problem)是在给定源点和汇点的情况下,找到从源点到汇点的最大可行流量,既满足流量守恒定律,又不超过每条边的容量约束。该问题在多个领域中有重要应用,如网络优化、交通流量控制、通信带宽分配、物流路径规划以及流体力学中的流体传输等。最大流问题的求解方法广泛用于提高资源分配效率和系统性能。

一、最大流问题概述

容量网络图1 Ford-Fulkerson 标号法

1.1 最大流问题的界定

给定指定的一个有向图G,其中有两个特殊的点:源点S(Sources)和汇点T(Sinks),源点就是入度为0的点,而汇点是出度为0的点,图的每条边有指定的权值代表最大容量(Capacity),研究这样的图的从源点到汇点的流量分配就是网络流问题。
容量网络和流:对网络上每一条弧都给出一个最大的通过能力, 称为该弧的容量 (capacity), 记为 \(c\left(v_i, v_j\right)\), 简记为 \(c_{i j}\), 并称该网络为容量网络。容量网络规定一个发点 (send) \(s\), 一个收点 (take) \(t\) 。流(flow)是指网络上各条弧的载荷量, 记为 \(f\left(v_i, v_j\right)\), 简记为 \(f_{i j}\) 。图 4-22 是连接某产品产地 \(v_s\) 和销地 \(v_t\) 的运输图。弧 \(\left(v_i, v_j\right)\) 表示从 \(v_i\)\(v_j\) 的运输线, 弧上括号内第 1 个数字表示这条运输线的最大通过能力 \(c_{i j}\), 括号内第 2 个数字表示该弧上的实际流 \(f_{i j}\)
可行流:对于给定的容量网络 \(D=(V, A, C)\) 和给定的流 \(f=\left\{f\left(v_i, v_j\right)\right\}\) ,若 \(f\) 满足下列条件:
(1) 容量限制条件, 对每一条弧 \(\left(v_i, v_j\right)\), 有 \(0 \leqslant f_{i j} \leqslant c_{i j}\);
(2) 流量平衡条件, 对于中间点, 流出量=流入量, 即对于每一个 \(i(i \neq s, t)\), 有

\[\begin{gathered} \sum_{\left(v, v_j\right) \in A} f_{i j}-\sum_{\left(v_j, v_i\right) \in A} f_{j i}=0 \\ \sum_{\left(v, v_j\right) \in A} f_{s j}=v(f) \\ \sum_{\left(v_j, v_i, \in A\right.} f_{j t}=v(f) \end{gathered} \]

对于发点 \(v_s\), 有$\sum_{j} f_{sj} - \sum_{j} f_{js} = v(f) \quad \text{for } i, j \neq s, t $
对于收点 \(v_t\), 有$\sum f_{t j}-\sum f_{j t}=-v(f) \quad \text{for } i, j \neq s, t $
则称 \(f=\left\{f_{i j}\right\}\) 为一个可行流, \(v(f)\) 称为这个可行流的流量。
注意: 这里所说的发点 \(v_s\) 是指只有从 \(v_s\) 发出去的弧, 而没有指向 \(v_s\) 的弧; 收点 \(v_t\) 只有指向 \(v_t\) 的弧,而没有从 \(v_t\) 发出去的弧。
可行流总是存在的, 例如, 令所有弧上的流 \(f_{i j}=0\), 就得到一个可行流(称为零流), 其流量 \(v(f)=0\) 。在图1中,每条弧上括号内的数字给出的就是一个可行流 \(f=\left\{f_{i j}\right\}\) ,它满足可行流定义中的条件(1)和(2), 其流量 \(v(f)=5+0+15=20\)
所谓网络最大流问题就是求一个流 \(f=\left\{f_{i j}\right\}\), 使得总流量 \(v(f)\) 达到最大, 并且满足可行流定义中的条件(1)和(2), 即

\[\begin{aligned} & \max v(f) \\ & \left\{\begin{array}{l} \sum_{(v, v, v,) \in A} f_{i j}-\sum_{(v, v, v, \in A} f_{j i}=0 \quad \forall i, j \notin\{s, t\} \\ \sum_{(v, s, v,) \in A} f_{s j}=v(f) \\ \sum_{(v, v, v) \in A} f_{j t}=v(f) \\ 0 \leqslant f_{i j} \leqslant c_{i j}(\forall i, j) \end{array}\right. \end{aligned} \]

网络最大流问题是一类特殊的线性规划问题,可以利用线性规划方法求解。这里将给出一种利用图的特点来解决这个问题的方法,相对而言比线性规划的一般方法要简便和直观得多。
饱和弧和零流弧:在网络 \(D=(V, A, C)\) 中,若给定一个可行流 \(f=\left\{f_{i j}\right\}\) ,将网络中 \(f_{i j}=c_{i j}\) 的弧称为饱和弧, 将 \(0 \leqslant f_{i j}<c_{i j}\) 的弧称为不饱和弧, 将 \(f_{i j}=0\) 的弧称为零流弧, 将 \(0<f_{i j} \leqslant c_{i j}\) 的弧称为非零流弧。
图1中的弧 \(\left(v_1, v_3\right)\) 是饱和弧; 弧 \(\left(v_1, v_t\right)\) 是不饱和弧; 弧 \(\left(v_s, v_3\right)\) 为零流弧。
前向弧后向弧:\(\mu\) 是网络中连接发点 \(v_s\) 和收点 \(v_t\) 的一条路, 定义路的方向是从 \(v_s\)\(v_t\), 则路上的弧被分为两类。
弧的方向与路的方向一致,称此类弧为前(或正)向弧,所有前向弧的集合记为 \(\mu^{+}\)。弧的方向与路的方向不一致,称此类弧为后(或逆)向弧,所有后向弧的集合记为 \(\mu^{-}\)。在图 4-22 中, \(\mu=\left\{v_s,\left(v_s, v_1\right), v_1,\left(v_2, v_1\right), v_2,\left(v_2, v_3\right), v_3,\left(v_3, v_t\right), v_t\right\}\) 是一条从 \(v_s\)\(v_t\) 的路,

\[\mu^{+}=\left\{\left(v_s, v_1\right),\left(v_2, v_3\right),\left(v_3, v_t\right)\right\}, \quad \mu^{-}=\left\{\left(v_2, v_1\right)\right\} \]

增广路:\(f=\left\{f_{i j}\right\}\) 是网络 \(D=(V, A, C)\) 上的一个可行流, \(\mu\) 是从 \(v_s\)\(v_t\) 的一条路, 若 \(\mu\) 满足下列条件:
(1) 在弧 \(\left(v_i, v_j\right) \in \mu^{+}\)上, 其流量 \(f_{i j}<c_{i j}\), 即 \(\mu^{+}\)中的每一条弧都是非饱和弧;
(2) 在弧 \(\left(v_i, v_j\right) \in \mu^{-}\)上, 其流量 \(f_{i j}>0\), 即 \(\mu^{-}\)中的每一条弧都是非零流弧, 则称 \(\mu\) 是关于 \(f\) 的一条增广路。
如前面提到的路 \(\mu=\left\{v_s,\left(v_s, v_1\right), v_1,\left(v_1, v_2\right), v_2,\left(v_2, v_3\right), v_3,\left(v_3, v_t\right), v_t\right\}\) 就是一条增广路, 因为其中 \(\mu^{+}\)上的弧均非饱和;而 \(\mu^{-}\)上的弧为非零流弧,显然这样的增广路不止一条。
截集:给定网络 \(D=(V, A, C)\) ,若点集 \(V\) 被分割成两个非空集合 \(V_1\)\(V_2\) ,使得 \(V=V_1 \cup V_2, V_1 \cap V_2=\varnothing\) (空集), 且 \(v_s \in V_1, v_t \in V_2\), 则把发点在 \(V_1\), 收点在 \(V_2\) 的弧的集合称为分离 \(v_s\)\(v_t\) 的一个截集,记为 \(\left(V_1, V_2\right)\)
在图1中, 设 \(V_1=\left\{v_s, v_1\right\}, V_2=\left\{v_2, v_3, v_t\right\}\), 则截集为

\[\left(V_1, V_2\right)=\left\{\left(v_s, v_2\right),\left(v_s, v_3\right),\left(v_1, v_3\right),\left(v_1, v_t\right)\right\} \]

参看图1中的虚线穿过的弧, 而弧 \(\left(v_2, v_1\right)\) 不是该集中的弧, 因为这条弧的起点在 \(V_2\) 中,与定义 4.15 要求不符。显然, 容量网络的截集有很多, 在图1中还可取 \(V_1^{\prime}=\left\{v_s, v_1, v_2\right\}, V_2^{\prime}=\left\{v_3, v_t\right\}\), 则截集为

\[\left(V_1^{\prime}, V_2^{\prime}\right)=\left\{\left(v_s, v_3\right),\left(v_1, v_3\right),\left(v_1, v_t\right),\left(v_2, v_3\right),\left(v_2, v_t\right)\right\} \]

若把网络 \(D=(V, A, C)\) 中某截集的弧从该网络中去掉, 则从 \(v_s\)\(v_t\) 便不存在路, 所以直观上说, 截集是从 \(v_s\)\(v_t\) 的必经之弧, 这也是截集命名的由来。
截量:在网络 \(D=(V, A, C)\) 中,给定一个截集 \(\left(V_1, V_2\right)\) ,则把该截集中所有弧的容量之和, 称为这个截集的容量, 简称截量, 记为 \(c\left(V_1, V_2\right)\), 即

\[c\left(V_1, V_2\right)=\sum_{\left(v_i, V_j\right) \in\left(V_1, V_2\right)} c_{i j} \]

例如, 在上面所举的两个截集中, 有

\[c\left(V_1, V_2\right)=c_{s 2}+c_{s 3}+c_{13}+c_{1 t}=20+30+5+20=75 \]

\[c\left(V_1^{\prime}, V_2^{\prime}\right)=c_{s 3}+c_{13}+c_{1 t}+c_{23}+c_{2 t}=30+5+20+40+30=125 \]

显然, 截集不同截量也不同。根据截集的定义, 截集的个数是有限的, 故其中必有一个截集的容量是最小的, 称为最小截集, 也就是通常所说的"瓶颈"。
残量图:带前向弧和反向弧的图称为残量图。

1.2 最大流问题的应用

最大流问题不仅是图论中的基础问题,而且在实际应用中具有重要的作用,以下是一些典型的应用领域:
通信网络:在数据通信中,最大流问题可用于优化带宽分配和网络路由,确保数据能够以最大速率从发送端传递到接收端,特别是在互联网流量控制和内容分发网络(CDN)中。
交通运输:交通规划中可以应用最大流模型来解决交通网络中的拥堵问题,找出在一定容量限制下,城市中车辆从起点到终点的最佳分流路径。
物流配送:在物流配送网络中,最大流模型可以帮助优化配送路径,确保货物以最快的速度从仓库运输到多个目的地。在多端网络中,最大流问题也可应用于多点配送的优化。
供水系统和电力系统:供水系统和电力系统中的资源调度可以使用最大流模型优化流量分配,确保资源能够以最优方式在网络中传输。
图像处理:在图像分割和计算机视觉中,最大流-最小割算法被用于图像的分割,通过找到图像区域之间的最小割来识别不同的物体和背景。

1.3 最大流问题的性质和定理

最大流-最小割定理(Max-Flow Min-Cut Theorem)是最大流问题中的重要理论,指出一个网络中的最大流等于该网络中将源点和汇点分开的最小割的总容量。流量守恒定律(Flow Conservation Law):该定律要求在网络的每一个节点上,除源点和汇点外,流入该节点的流量必须等于流出该节点的流量。这是确保流量平衡的关键约束条件。
定理1 在网络 \(D=(V, A, C)\) 中, 可行流 \(f^*=\left\{f_{i j}^*\right\}\) 是最大流的充要条件是 \(D\) 中不存在关于 \(f^*\) 的增广路。
定理2 (最大流-最小截集定理)对于任意给定的网络 \(D=(V, A, C)\), 从发点 \(v_s\) 到收点 \(v_t\) 的最大流的流量必等于分割 \(v_s\)\(v_t\) 的最小截集 \(\left(V_1^*, V_2^*\right)\) 的容量, 即

\[v\left(f^*\right)=c\left(V_1^*, V_2^*\right) \]

二、最大流问题的Python实现

求解最大流问题主要有几种常见算法:

福特-弗尔克森算法(Ford-Fulkerson Algorithm):该算法基于增广路的思想,通过寻找残余网络中的增广路径,逐步增加流量,直到无法再找到增广路径为止。这个算法的效率依赖于如何选择增广路径。
Edmonds-Karp算法:该算法是福特-弗尔克森算法的改进,使用广度优先搜索(BFS)来寻找增广路径,因此具有明确的时间复杂度 \(O(VE^2)\),其中 \(V\) 是节点数,\(E\) 是边数。
Dinic算法:该算法基于分层网络,通过在残余网络中创建分层图,并通过分层图进行多条增广路径的并行计算,从而提高了效率,时间复杂度为 \(O(V^2E)\)
推-重标算法(Push-Relabel Algorithm):这是另一种求解最大流的算法,通过局部的流量调整(推送)和对节点的高度进行重新标记(重标),从而逐步优化流量分配。它的时间复杂度为 \(O(V^3)\)

2.1 最大流问题求解算例1

该算法在残量图中寻找增广路径基于图的BFS遍历,即广度优先搜索(Breadth-First Search)遍历,是一种遍历或搜索树或图的算法。通过BFS遍历不断在残量图中寻找增广路径。

  • 增广路径1

  • 增广路径2

  • 增广路径3

  • 求解完成

2.2 最大流问题Python求解

求解下面的最大流问题

容量网络 最大流网络
from collections import defaultdict, deque
import networkx as nx
import matplotlib.pyplot as plt# 定义一个图的类
class Graph:def __init__(self, vertices):self.V = vertices  # 节点数self.graph = defaultdict(list)  # 图的邻接表表示self.capacity = {}  # 容量self.flow = defaultdict(int)  # 存储流量# 添加边和其对应的容量def add_edge(self, u, v, capacity):self.graph[u].append(v)self.graph[v].append(u)  # 反向边self.capacity[(u, v)] = capacityself.capacity[(v, u)] = 0  # 反向边容量为0# 使用广度优先搜索(BFS)查找增广路径def bfs(self, source, sink, parent):visited = [False] * self.Vqueue = deque([source])visited[source] = Truewhile queue:u = queue.popleft()for v in self.graph[u]:if not visited[v] and self.capacity[(u, v)] > 0:  # 容量大于0表示可以继续queue.append(v)visited[v] = Trueparent[v] = uif v == sink:return Truereturn False# 使用Edmonds-Karp算法计算最大流def edmonds_karp(self, source, sink):parent = [-1] * self.Vmax_flow = 0while self.bfs(source, sink, parent):path_flow = float("Inf")s = sink# 找到路径中的最小容量while s != source:path_flow = min(path_flow, self.capacity[(parent[s], s)])s = parent[s]# 更新残余图和记录流量v = sinkwhile v != source:u = parent[v]self.capacity[(u, v)] -= path_flowself.capacity[(v, u)] += path_flowself.flow[(u, v)] += path_flow  # 更新流量self.flow[(v, u)] -= path_flow  # 更新反向流量v = parent[v]max_flow += path_flowreturn max_flow# 创建图
g = Graph(6)  # 6个顶点# 根据图中的容量添加边
g.add_edge(0, 1, 16)  # s -> v1
g.add_edge(0, 2, 13)  # s -> v2
g.add_edge(1, 3, 12)  # v1 -> v3
g.add_edge(2, 1, 4)   # v2 -> v1
g.add_edge(2, 4, 14)  # v2 -> v4
g.add_edge(3, 2, 9)   # v3 -> v2
g.add_edge(3, 5, 20)  # v3 -> t
g.add_edge(4, 3, 7)   # v4 -> v3
g.add_edge(4, 5, 4)   # v4 -> t# 计算从源点(0)到汇点(5)的最大流
source = 0  # s
sink = 5    # t
max_flow = g.edmonds_karp(source, sink)print(f"图中从源点到汇点的最大流为: {max_flow}")# 绘制图形
def draw_graph():G = nx.DiGraph()  # 使用有向图# 添加图的边和对应容量edges = [(0, 1, 16), (0, 2, 13),(1, 3, 12), (2, 1, 4), (2, 4, 14),(3, 2, 9), (3, 5, 20),(4, 3, 7), (4, 5, 4)]# 添加边到NetworkX图中for u, v, w in edges:G.add_edge(u, v, capacity=w, flow=g.flow[(u, v)])  # 使用 g.flow 来添加流量# 手动设置各个节点的位置,层次化布局pos = {0: (0, 2),   # s1: (1, 3),   # v12: (1, 1),   # v23: (2, 3),   # v34: (2, 1),   # v45: (3, 2)    # t}# 绘制节点nx.draw(G, pos, with_labels=True, node_color='lightblue', node_size=3000, font_size=16, font_weight='bold')# 获取容量和流量标签 (流量, 容量)edge_labels = {(u, v): f'({d["flow"]},{d["capacity"]})' for u, v, d in G.edges(data=True)}# 绘制边权重(流量, 容量)和边的标签nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=12, font_color='red')nx.draw_networkx_edges(G, pos, width=2, edge_color='black', arrows=True, arrowsize=20)plt.title("Flow Network with Flows and Capacities", fontsize=20)plt.show()# 调用函数绘制图
draw_graph()
从源点到汇点的最大流为: 23

总结

容量网络(Capacity Network)是一种特殊的有向图结构,其中每条边都有一个容量(Capacity),表示该边上可以通过的最大流量。在这种网络中,流量(Flow)是指从源点(Source)通过边到达汇点(Sink)的实际传输量。容量网络中的边具有方向性,且每条边的流量不能超过其容量。最大流问题(Maximum Flow Problem)是在给定源点和汇点的情况下,找到从源点到汇点的最大可行流量,既满足流量守恒定律,又不超过每条边的容量约束。该问题在多个领域中有重要应用,如网络优化、交通流量控制、通信带宽分配、物流路径规划以及流体力学中的流体传输等。最大流问题的求解方法广泛用于提高资源分配效率和系统性能。

随着网络技术、优化理论和算法研究的不断进步,最大流问题也在不断发展,尤其是在以下几个方向:
动态网络最大流问题:传统的最大流问题假设网络是静态的,即网络结构和容量不随时间变化。然而,在现实世界中,许多网络是动态的,如交通网络、通信网络等。动态最大流问题研究如何在网络变化时实时调整流量。
随机网络最大流问题:在许多应用中,网络的容量和结构并不确定,如在通信网络中,链路的带宽可能随时间波动。随机网络最大流问题研究在随机环境中,如何找到期望的最大流。
并行和分布式最大流算法:随着大规模网络的出现,传统的最大流算法难以处理海量数据。并行和分布式算法可以在多核处理器或集群上运行,以提高求解效率,适应大规模网络的需求。

参考资料

  1. 最大流问题和Edmonds-Karp算法
  2. 最大流(Max Flow)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/795654.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中的数组,字符串数组,pair数组

1.C++中的字符串数组: 2. C++中的常量数组 这个const pair<int, string> valueSymbols[]定义了一个常量数组,数组中的每个元素都是一个pair<int, string>类型的对象。pair是C++标准模板库(STL)中的一个模板类,用于将两个值组合成一个单一的对象。在这个特定的…

TensorFlow深度学习框架改进K-means、SOM自组织映射聚类算法及上海招生政策影响分析研究|附代码数据

全文链接:https://tecdat.cn/?p=37652 原文出处:拓端数据部落公众号 分析师:Chen Zhang在教育政策研究领域,准确评估政策对不同区域和学生群体的影响至关重要。2021 年上海市出台的《上海市初中学业水平考试实施办法》对招生政策进行了调整,其中名额分配综合评价模块的…

【python脚本】springboot检测脚本

原创 CatalyzeSecimport requests import urllib3 urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) session = requests.session()# 从文本文件中读取 with open(dic.txt, r) as file:paths = file.readlines()# 移除每个末尾的换行符 paths = [path.str…

STM32学习笔记——中断

中断:在主程序运行过程中,出现了特定事件(例如发生已经预知的一些情况),从而转入中断程序中,处理完成后再回到主程序中继续执行。(频繁的中断函数会影响主程序的运行,所以中断函数一边不处理特别复杂的逻辑) EXTI(Extern Interrupt)外部中断 支持的触发方式:上升沿…

面试-JS Web API-DOM

概览DOM(Document Object Model)DOM是哪种数据结构? ---树🌳 常用的API attr和property区别 一次性插入多个DOM节点?DOM节点操作DOM节点的property 通过获取JS属性来改变样式or页面渲染形式。DOM节点的attribute 修改节点的属性。建议尽量用property操作。

送给测试行业朋友们的一些中肯建议

在快速发展的科技时代,软件测试行业也在不断变化。如果你是一名测试人员,或正在考虑进入这个行业,你是否感到迷茫?该如何提升自己,以应对未来的挑战?今天,我为所有测试行业的朋友们带来一些切实的建议,助你们走得更远。 作为测试人员,你是否经常面对需求变化、测试工具…

【Azure Cloud Service】在Azure云服务中收集CPU监控指标和IIS进程的DUMP方法

问题描述 在使用Cloud Service服务时,发现服务的CPU占用很高,在业务请求并不大的情况下,需要直到到底是什么进程占用了大量的CPU资源,已经如何获取IIS进程(w3wp.exe)的DUMP文件?问题解答 一:收集云服务中CPU的性能数据 远程登录(RDP)到云服务的实例上,使用管理员身份运行…

Blazor开发框架Known-V2.0.10

Known今天迎来了2.0的第11个版本,同时网站网址和板块也进行了一次升级改造,虽不完美,但一直在努力改变,之前一直在完善框架功能,忽略了文档的重要性,所以这次更新了文档和API。交流互动板块也在进行当中,尽请期待。官方网站:http://known.org.cn 最新版本:V2.0.10下面…

个人项目:论文查重

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13229这个作业的目标 独立完成一个论文查重的个人项目;在项目开发中学习PSP表格的使用;学习使用Github仓库进行代码管…

Cesium源码解读之Viewer(全网最全)

今天我们来扒一扒cesium 的源码, 探寻一下底层的奥秘,我们平时工作中用的最多的应该就是var viewer = new Cesium.Viewer(cesiumContainer);这句了但我们却很少去了解他底层是否如何实现的。 首先 我们可以通过Source/Cesium.js找到api 的入口然后一步步往下走.... 这个是我理…

关闭默认WPS打开方式

原文链接:https://blog.csdn.net/Candy_SJ_/article/details/139898009 文件默认为wps打开,有时候有很多问题。关闭wps默认打开方式 还是有问题,我这边是将wps卸载了。