首页 > 其他分享 >图与网路——最大流问题精解

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

时间:2024-09-11 20:47:50浏览次数:8  
标签:right 最大 容量 self 网络 流量 精解 网路 left

容量网络(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)] = capacity
        self.capacity[(v, u)] = 0  # 反向边容量为0

    # 使用广度优先搜索(BFS)查找增广路径
    def bfs(self, source, sink, parent):
        visited = [False] * self.V
        queue = deque([source])
        visited[source] = True

        while 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] = True
                    parent[v] = u
                    if v == sink:
                        return True
        return False

    # 使用Edmonds-Karp算法计算最大流
    def edmonds_karp(self, source, sink):
        parent = [-1] * self.V
        max_flow = 0

        while 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 = sink
            while v != source:
                u = parent[v]
                self.capacity[(u, v)] -= path_flow
                self.capacity[(v, u)] += path_flow
                self.flow[(u, v)] += path_flow  # 更新流量
                self.flow[(v, u)] -= path_flow  # 更新反向流量
                v = parent[v]

            max_flow += path_flow

        return 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),   # s
        1: (1, 3),   # v1
        2: (1, 1),   # v2
        3: (2, 3),   # v3
        4: (2, 1),   # v4
        5: (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["capacity"]}, {d["flow"]})' 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='black')
    nx.draw_networkx_edges(G, pos, width=2, edge_color='black', arrows=True, arrowsize=20)

    plt.title("Flow Network with Capacities and Flows", fontsize=20)
    plt.show()

# 调用函数绘制图
draw_graph()
从源点到汇点的最大流为: 23

总结

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

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

参考资料

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

标签:right,最大,容量,self,网络,流量,精解,网路,left
From: https://www.cnblogs.com/haohai9309/p/18408632

相关文章

  • 代码随想录训练营day44|1143.最长公共子序列,1035.不相交的线, 53. 最大子序和,392.判
    1143.最长公共子序列这题并不要求连续子序列的要求是可以删除某些元素,但不能改变顺序。顺着上题的思路,这题也应该设立一个二维数组vector<vector<int>>dp(text1.size(),vector<int>(text2.size(),0));dp[i][j]表示的是以text1[i]为结尾的字符串和以text2[j]为结尾的......
  • 滑动窗口&动态规划-1031. 两个非重叠子数组的最大和
    问题描述问题求解本题还挺巧妙,有点类似两数和的扩展题。对于两个线段,我们可以固定右线段,然后寻找左线段的最大值。固定右线段使用到的算法是滑动窗口,寻找左线段最大值的算法是动态规划。时间复杂度:O(n)classSolution:defmaximizeWin(self,prizePositions:List[int......
  • 最大熵原理[解释+例题]
    1熵的概念熵是热力学中的一个概念,由香浓引入到信息论中。在信息论中,熵是衡量随机变量不确定性的量度,熵越大表示随机变量的不确定性越大,即随机变量越难以预测。2熵的计算信息熵的计算可以看笔者的博客:点此跳转。3最大熵原理定义最大熵原理是一种选择随机变量统计特性最符......
  • 图与网络——最短路问题精解
    最短路问题(ShortestPathProblem)是图论中的一个经典问题,广泛应用于现实世界中的多个领域。该问题的核心在于如何在一个图中找到给定起点和终点之间路径权重最小的路径。路径权重通常代表时间、成本、距离等因素,因此最短路问题不仅具有理论上的研究价值,还在实际问题的解决中发挥了......
  • 贪心算法day28|买卖股票的最佳时机、55. 跳跃游戏、1005. K 次取反后最大化的数组和
    贪心算法day28|买卖股票的最佳时机、55.跳跃游戏、1005.K次取反后最大化的数组和122.买卖股票的最佳时机II55.跳跃游戏1005.K次取反后最大化的数组和122.买卖股票的最佳时机II给你一个整数数组prices,其中prices[i]表示某支股票第i天的价格。在每一......
  • 图与网络——最小树问题精解
    最小生成树(MinimumSpanningTree,MST)问题是图论中的一个重要问题,其核心思想是:给定一个无向加权图(每条边具有权重值),通过选择若干边构建一棵包含所有顶点的生成树,并确保这些边的权重总和最小。最小生成树不仅保持了生成树的连通性和无圈性,还要求总权重最小化。在实际应用中,最小生......
  • 【大数据】如何读取多个Excel文件并计算列数据的最大求和值
    导语:在数据分析和处理中,我们经常需要从多个Excel文件中提取数据并进行计算。本文将带您通过一个实用的Python教程,学习如何读取D盘目录下特定文件夹内的多个Excel文件,并计算特定列数据的最大求和值。文章目录一、准备工作二、教程步骤1.导入必要的库2.设置文件路径3.......
  • 树状数组求区间最大小值
    constintN=5e5+5;constintINF=0x3f3f3f3f;intn,q;inta[N],trmx[N],trmn[N];//将原来的累加改为求最值voidadd(intx,intk){while(x<=n){trmx[x]=max(trmx[x],k);trmn[x]=min(trmn[x],k);x+=lowbit(x);}}//区间查询最大/小值......
  • P5745【深基附B例】区间最大和
    思路一:枚举区间头尾i,j,然后对i和j里面所有数字累加起来求和,再判断是否在不大于M的情况下最大。#include<iostream>usingnamespacestd;inta[8000005];intmain(){ intn,M,ansm=0,ai,aj; cin>>n>>M; for(inti=1;i<=n;i++){ cin>>a[i]; } for......
  • 图与网络模型的基本概念精解
    图是一种最简单且直观的语言,它通过点和线的组合来表达复杂系统中的关系。点代表对象或位置,线代表它们之间的连接或交互。这种简洁的表达方式使得图在众多领域中具有强大的应用能力。无论是社交网络中的好友关系、城市中的交通系统,还是生物学中的基因网络,图都能通过简单的结构,呈现......