【网络流】最大流与Ford–Fulkerson算法

news2024/9/22 17:18:54

目录

  • 一、引言
    • 1.1 网络流问题
    • 1.2 “流”的定义
    • 1.3 “割”的定义
  • 二、最大流最小割
    • 2.1 最大流
    • 2.2 最小割
    • 2.3 最大流最小割定理
    • 2.4 最大流最小割定理证明
  • 三、Ford–Fulkerson算法
    • 3.1 增广路径
    • 3.2 剩余图
    • 3.3 算法代码
    • 3.4 FordFulkerson Demo

一、引言

1.1 网络流问题

网络流问题是图论中的一个重要问题,通常用于描述在网络中物质、信息或资源的流动。它通常建模为一个图,由节点和边构成。

在这里插入图片描述

网络流问题包括两个主要方面:网络的结构和流量限制。一般情况下,网络流问题被建模为一个有向图,其中节点表示资源的位置,边表示资源在节点之间的流动路径。每条边都有一个容量限制 (Capacity),表示该路径上能够通过的最大流量。此外,还有源节点 (Source) 和汇点 (Sink) ,分别代表资源的产生地和消耗地。

形式上,我们说一个流网络是具有下述特征的有向图 G=(V,E)

  • 每条边 e 关联一个容量,它是一个非负的数,把它记作 c e c_e ce
  • 存在单一源点 s ∈ V s\in V sV
  • 存在单一汇点 t ∈ V t\in V tV
  • st 之外的其他结点叫做内部结点

网络流问题有多种形式,其中最经典的是最大流 (max-flow)最小割 (min-cut) 问题。

为了使网络流处理更加方便,我们引入三个假设来简化问题:

  1. 没有边进入源点 s ,且没有边离开汇点 t
  2. 每个结点至少存在一条边与之连接
  3. 所有的容量都是整数

1.2 “流”的定义

“网络运送交通” 或者 “流” 的含义是什么。我们说一个 s-t 流是一个函数 f,它把每条边e映射到一个非负实数: f : E → R + f:E\rightarrow R^+ f:ER+ f ( e ) f(e) f(e) 直观上表示由边e携带的流量。一个流必须满足下面两个性质:

  1. (容量条件) 对每个 e ∈ E e\in E eE ,我们有 0 ≤ f ( e ) ≤ c e 0\le f(e)\le c_e 0f(e)ce
  2. (守恒条件) 除了 st 之外,对每个结点 v v v ,我们有 ∑ e 进入 v f ( e ) = ∑ e 从 v 出来 f ( e ) \sum_{e进入v}f(e)=\sum_{e从v出来}f(e) e进入vf(e)=ev出来f(e)

即一条边上的流不能超过这条边的容量
除了源点和汇点以外,对每个其他结点,进人的流量必须等于离开的流量

一个流 f f f 的值,记作 v ( f ) v(f) v(f) ,定义成在源点产生的流量 v ( f ) = ∑ e 从 s 出来 f ( e ) = f o u t ( s ) v(f)=\sum_{e从s出来}f(e)=f^{out}(s) v(f)=es出来f(e)=fout(s)

1.3 “割”的定义

考虑把图的结点 v v v 分成两个集合:AB,使得 s ∈ A s\in A sA t ∈ B t\in B tB
对于图上的所有的一定在某个地方从 A 跨到 B
形式上,我们说一个 s-t 割是结点集合 v v v 的一个划分 (A,B) ,使得 s ∈ A s\in A sA t ∈ B t\in B tB
一个割(A,B)的容量记为: c ( A , B ) c(A,B) c(A,B) ,只不过是从 A 出来的所有边的容量之和: c ( A , B ) = ∑ e 从 A 出来 c e c(A,B)=\sum_{e从A出来}c_e c(A,B)=eA出来ce


二、最大流最小割

2.1 最大流

给定一个流网络,一个自然的目标就是安排交通以使得有效容量尽可能得到有效的使用。于是,我们将在下面考虑的基本算法问题是:给定一个流网络,找出一个具有最大值的流,即在网络中找到一条从源节点到汇节点的路径,使得沿该路径的流量总和最大化,同时满足每条边的流量限制。

一个最简单的论断是:任何 s-t 流 f f f 的值 v ( f ) v(f) v(f) 至多是 C = ∑ e 从 s 出来 c e C=\sum_{e从s出来}c_e C=es出来ce
如下图所示,我们可以快速得到 v ( f ) = 10 + 5 + 15 = 30 v(f)=10+5+15=30 v(f)=10+5+15=30 作为网络流的上界。
但大多时候这个上界是非常弱的,可以使用割的概念来发展一个更一般的手段来设置最大流值的上界。

在这里插入图片描述

2.2 最小割

假设我们把一张网络流图的结点划分成两个子集:AB,使得 s ∈ A s\in A sA t ∈ B t\in B tB 。那么从到的任何流直观上必须在某个点从 A 穿到 B ,因此用完了从 AB 的某些边的容量。这提醒我们,这个图的每个这样的“割”对最大的流值设立了一个界。也就是说最小割表示从源节点到汇节点的最小流量限制,当这个限制被破坏时,网络将被切割成两个部分。

在这里插入图片描述

2.3 最大流最小割定理

在这里插入图片描述
从上图不难看出,最大流和最小割冥冥之中存在很强的相关性。先说结论,其实最大流和最小割是等价的。

定理 1:令 f f f 是任何 s-t 流,且 (A,B) 是任意 s-t 割。那么 v ( f ) = f o u t ( A ) − f i n ( A ) v(f)=f^{out}(A)-f^{in}(A) v(f)=fout(A)fin(A)

这个论断比起之前那个简单的上界要强的多。它是说,通过观察跨过一个割送出的流量,我们恰好可以计算流的值,即离开 A 的流的总量 减去 “返回”进入 A 的总量

同理也可以得到 定理 1 的另外一个版本: v ( f ) = f i n ( B ) − f o u t ( B ) v(f)=f^{in}(B)-f^{out}(B) v(f)=fin(B)fout(B)

定理 2:令 f f f 是任何 s-t 流,且 (A,B) 是任意 s-t 割。那么 v ( f ) ≤ c ( A , B ) v(f) \le c(A,B) v(f)c(A,B)

证明: v ( f ) = f o u t ( A ) − f i n ( A ) ≤ f o u t ( A ) = ∑ e 从 A 出来 f ( e ) ≤ ∑ e 从 A 出来 c ( e ) = c ( A , B ) v(f)=f^{out}(A)-f^{in}(A)\le f^{out}(A)=\sum_{e从A出来}f(e)\le \sum_{e从A出来}c(e)=c(A,B) v(f)=fout(A)fin(A)fout(A)=eA出来f(e)eA出来c(e)=c(A,B)

定理2 说的是每个流的值是以每个割的容量为上界的,换句话说,如果我们展示了 G 中任何具有某个值 c ∗ c^* c 的 s-t 割,由定理2 我们立刻就知道 G 中不可能有任何值大于 c ∗ c^* c 的 s-t 流

f ˉ \bar f fˉ 为 G 中任何流的最大可能值; ( A ∗ , B ∗ ) (A^*,B^*) (A,B) 为任何割的最小容量。

Max-flow Min-cut Theorem:

如果 f ˉ \bar f fˉ 是使得在剩余图 G f G_f Gf 中没有 s-t 路径(无增广路径)的一个 s-t 流
那么在 G 中存在一个割 ( A ∗ , B ∗ ) (A^*,B^*) (A,B)
使得 v ( f ˉ ) = c ( A ∗ , B ∗ ) v(\bar f)=c(A^*,B^*) v(fˉ)=c(A,B)

因此, f ˉ \bar f fˉ 有 G 中任何流的最大值,且 ( A ∗ , B ∗ ) (A^*,B^*) (A,B) 有 G 中任何 s-t 割的最小容量.

2.4 最大流最小割定理证明

上述定理声称存在着满足某条所要求性质的割;我们的任务就是找出这样一个割。
A ∗ A^* A 表示 G f G_f Gf中存在一条 s-v 路径的所有结点 v v v 的集合
B ∗ B^* B 是所有其他结点的集合: B ∗ = V − A ∗ B^*=V-A^* B=VA

  • 显然 ( A ∗ , B ∗ ) (A^*,B^*) (A,B) 的确是 s-t 割,它是结点集合 V V V 的划分,且源点 s ∈ A ∗ s\in A^* sA ; 汇点 t ∈ B ∗ t \in B^* tB

如下图所示

  1. 假设 e = ( u , v ) e=(u,v) e=(u,v) 是 G 中一条边,并且使得 u ∈ A ∗ u\in A^* uA v ∈ B ∗ v\in B^* vB
    f ( e ) = c e f(e)=c_e f(e)=ce ,即该条边的流等于边的容量。
    • 如果 f ( e ) ≠ c e f(e)\ne c_e f(e)=ce , e e e 将是剩余图 G f G_f Gf 中一条前向边,由于 u ∈ A ∗ u\in A^* uA,设在 G f G_f Gf 中存在一条 s-u 的路径
      再把 e 接到这条路径上,我们将得到 G f G_f Gf 中一条 s-v 路径,与我们假设 v ∈ B ∗ v\in B^* vB 矛盾

在这里插入图片描述

  1. 假设 e ′ = ( u ′ , v ) e'=(u',v) e=(u,v) 是 G 中的一条边,并且使得 u ′ ∈ B ∗ u'\in B^* uB v ′ ∈ A ∗ v'\in A^* vA
    f ( e ) = 0 f(e)=0 f(e)=0 ,即该条边的流为0。

    • 如果 f ( e ′ ) ≠ 0 f(e')\ne 0 f(e)=0 , e ′ e' e 将在剩余图 G f G_f Gf 中产生一条后向边 e ′ ′ = ( v ′ , u ′ ) e''=(v',u') e′′=(v,u),由于 v ′ ∈ A ∗ v'\in A^* vA,设在 G f G_f Gf 中存在一条 s-v’ 的路径。再把 e ′ ′ e'' e′′ 接到这条路径上,我们将得到 G f G_f Gf 中一条 s-u’ 路径,与我们假设 u ′ ∈ B ∗ u'\in B^* uB 矛盾
  2. 因此所有从 A ∗ A^* A 出来的边完全充满了流,而所有进入 A ∗ A^* A 的边则完全没有用过 v ( f ˉ ) = f o u t ( A ∗ ) − f i n ( A ∗ ) = ∑ e 从 A ∗ 出来 f ( e ) − ∑ e 进入 A ∗ f ( e ) = ∑ e 从 A ∗ 出来 c e − 0 = c ( A ∗ , B ∗ ) v(\bar f)=f^{out}(A^*)-f^{in}(A^*)=\sum_{e从A^*出来}f(e)-\sum_{e进入A^*}f(e)\\\quad\\=\sum_{e从A^*出来}c_e-0=c(A^*,B^*) v(fˉ)=fout(A)fin(A)=eA出来f(e)e进入Af(e)=eA出来ce0=c(A,B)


三、Ford–Fulkerson算法

Ford–Fulkerson Algorithm (FFA) 是一种贪婪算法,用于计算流网络中的最大流。 它有时被称为“方法”而不是“算法”,因为在剩余图中查找增广路径的方法尚未完全指定,或者在具有不同运行时间的多个实现中指定。

它由 L. R. Ford Jr. 和 D. R. Fulkerson 于 1956 年出版。“Ford–Fulkerson”这个名称通常也用于 Edmonds–Karp 算法,它是 Ford–Fulkerson 方法的完全定义的实现。 该算法背后的思想如下:只要存在从源(起始节点)到汇点(结束节点)的路径,并且路径中所有边上都有可用容量,我们就沿着其中一条路径发送流量。 然后我们找到另一条路,依此类推。 具有可用容量的路径称为增广路径。

在这里插入图片描述


3.1 增广路径

增广路径(Augmenting Path)是在网络流问题中,从源节点到汇节点的一条路径,沿途的边上还有剩余容量可以增加流量的路径。增广路径具有以下特点:

  1. 起始于源节点
  2. 终止于汇节点
  3. 剩余容量大于0

在解决最大流问题时,寻找增广路径是Ford-Fulkerson算法的核心步骤。FFA算法依赖于不断寻找增广路径来增加流量,直到无法找到增广路径为止,从而找到最大流。

在这里插入图片描述

3.2 剩余图

剩余图(Residual Graph)是在Ford-Fulkerson算法中用于反映当前流量状态的图。它基于原始网络图构建,用于指示在增广路径上增加流量的可能性

剩余图的构建方式如下:

  • 正向边:对于每条原始图中的边,其残余容量表示该边上还能增加的流量。如果某条边上的流量小于其容量,那么在剩余图中就会有一条边,其容量等于该边的容量减去当前流量。
  • 反向边:为了支持反向流,即使在原始图中不存在反向的边,也会在剩余图中创建反向边。这些反向边的容量等于原始图中对应边上的流量,因为可以减少流量或者撤销之前的流。

在这里插入图片描述


3.3 算法代码

import collections

class Graph:
    """
    This class represents a directed graph using
    adjacency matrix representation.
    """

    def __init__(self, graph):
        self.graph = graph  # residual graph
        self.row = len(graph)

    def bfs(self, s, t, parent):
        """
        Returns true if there is a path from
        source 's' to sink 't' in residual graph.
        Also fills parent[] to store the path.
        """

        # Mark all the vertices as not visited
        visited = [False] * self.row

        # Create a queue for BFS
        queue = collections.deque()

        # Mark the source node as visited and enqueue it
        queue.append(s)
        visited[s] = True

        # Standard BFS loop
        while queue:
            u = queue.popleft()

            # Get all adjacent vertices of the dequeued vertex u
            # If an adjacent has not been visited, then mark it
            # visited and enqueue it
            for ind, val in enumerate(self.graph[u]):
                if (visited[ind] == False) and (val > 0):
                    queue.append(ind)
                    visited[ind] = True
                    parent[ind] = u

        # If we reached sink in BFS starting from source, then return
        # true, else false
        return visited[t]

    # Returns the maximum flow from s to t in the given graph
    def edmonds_karp(self, source, sink):
        # This array is filled by BFS and to store path
        parent = [-1] * self.row

        max_flow = 0  # There is no flow initially

        # Augment the flow while there is path from source to sink
        while self.bfs(source, sink, parent):
            # Find minimum residual capacity of the edges along the
            # path filled by BFS. Or we can say find the maximum flow
            # through the path found.
            path_flow = float("Inf")
            s = sink
            while s != source:
                path_flow = min(path_flow, self.graph[parent[s]][s])
                s = parent[s]

            # Add path flow to overall flow
            max_flow += path_flow

            # update residual capacities of the edges and reverse edges
            # along the path
            v = sink
            while v != source:
                u = parent[v]
                self.graph[u][v] -= path_flow
                self.graph[v][u] += path_flow
                v = parent[v]

        return max_flow

3.4 FordFulkerson Demo

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【教学类-43-13】 20240103 (4宫格数独:错误版:768套) 不重复的基础模板数量:768套

作品展示:——4宫格 768套不重复模板(64页*12套题) 有错误,实际数量小于768套 背景需求: 测试4宫格数独基础模板有几种。 写个程序,验算是不是真的是乘阶法的288种。 代码展示: 768套4宫格题…

AI原生应用开发“三板斧”亮相WAVE SUMMIT+2023

面对AI应用创新的风口跃跃欲试,满脑子idea,却苦于缺乏技术背景,不得不望而却步,这曾是许多开发者的苦恼,如今正在成为过去。 12月28日,WAVE SUMMIT深度学习开发者大会2023在北京举办。百度AI技术生态总经理…

【Java 基础】-- 实例化

1、定义 创建对象的过程就叫实例化。这个过程中会在堆中开辟内存,将一些非静态的方法,变量存放在里面。在程序执行的过程中,可以创建多个对象,既多次实例化。每次实例化都会开辟一块新的内存。 2、实例化的几种方法 new 关键字创…

STM32学习笔记十七:WS2812制作像素游戏屏-飞行射击游戏(7)探索动画之故事板,复杂动画

要让物体沿着路径移动,必须同时修改X/Y两个值,用两个连续插值动画行不行? 在单片机这种单线程设备,两个TICK会前后脚进行修改,具有相同的时间跨度,所以似乎也是可以的。但是在支持多线程的设备&#xff0c…

【CVPR2023】使用轻量 ToF 传感器的单目密集SLAM的多模态神经辐射场

目录 导读 本文贡献 本文方法 轻量级ToF传感器的感知原理 多模态隐式场景表示 时间滤波技术 实验 实验结果 消融实验 结论 未来工作 论文标题:Multi-Modal Neural Radiance Field for Monocular Dense SLAM with a Light-Weight ToF Sensor 论文链接&am…

Java程序设计阶段测试1

一、单选题(共15题; 共30.0分) 2.0分 1、以下哪个是Java应用程序main方法的有效定义? A.public static void main(); B.public static void main( String args ); C.public static void main( String args[] ); D.public static boolea…

交换机02_共享式交换式

1、共享式网络 早期的以太网是共享式网络,它是由集线器(HUB)相连,由一个HUB相连了两台主机,形成一个冲突域也称广播域。 (1)相关名词解释 集线器 HUB中心的意思,集线器就是对接收…

VINS-MONO拓展1----手写后端求解器,LM3种阻尼因子策略,DogLeg,构建Hessian矩阵

文章目录 0. 目标及思路1. 非线性优化求解器2. 基于VINS-MONO的Marginalization框架构建Hessian矩阵2.1 estimator.cpp移植2.2 solve.cpp/preMakeHessian()2.3 solve.cpp/makeHessian() 3. solve.cpp/solveLinearSystem()求解正规方程4. 更新状态5. 迭代求解6. EVO评估结果7. 待…

drf知识--10

接口文档 # 后端把接口写好后: 登录接口:/api/v1/login ---> post---name pwd 注册接口 查询所有图书带过滤接口 # 前后端需要做对接,对接第一个东西就是这个接口文档,前端照着接口文档开发 公司3个人&#xff…

LaTeX语法、工具及模板大全(持续更新ing...)

诸神缄默不语-个人CSDN博文目录 我之前把Markdown和LaTeX的语法写在一个博文里了,但是现在感觉还是应该拆开来比较合适,因为LaTeX太复杂了…… LaTex核心其实是套模板,但是为了套好模版,也需要学习一些具体的语法。 文章目录 1.…

14 简约登录页

效果演示 实现了一个简单的登录表单的样式,包括背景颜色、边框、字体颜色、字体大小、字体粗细、输入框样式、提交按钮样式等。当用户在输入框中输入内容时,输入框下方的提示文字会动态地变化,以提示用户输入正确的信息。当用户点击提交按钮时…

广播及代码实现

广播(Broadcast)是一种网络通信方式,它允许一台设备向网络中的所有其他设备发送消息。广播通常用于在网络上传递一些信息,让所有设备都能接收并处理。在广播中,通信的目标是整个网络而不是特定的单个设备。 向子网中…

电风扇目标检测数据集VOC格式1100张

电风扇的全方位介绍 一、功能特性 电风扇作为一种晋及化的家用电器,其主要功能是利用电机驱动扇叶旋转,从而产生风力,用干调节室内空气流通,达至降温、通风和改善室内环境的目的。此外,现代电风扇还具备定时、遥控、…

踩坑记录-安装nuxt3报错:Error: Failed to download template from registry: fetch failed;

报错复现 安装nuxt3报错:Error: Failed to download template from registry: fetch failednpx nuxi init nuxt-demo 初始化nuxt 项目 报错 Error: Failed to download template from registry: fetch faile 解决方法 配置hosts Mac电脑:/etc/hostswin电…

vue本地打包预览

1、项目打包 npm run build2、安装serve npm install -g serve3、在项目的 dist 文件运行命令行 serve 4、运行如下在浏览器打开即可

游戏用代理IP怎么检查是否有效?哪些因素会影响代理IP的质量?

随着网络游戏的普及,越来越多的玩家选择使用代理IP来提升游戏体验。然而,在使用代理IP的过程中,玩家们可能会遇到一些问题,其中最关键的就是如何检查代理IP是否有效以及哪些因素会影响代理IP的质量。本文将详细介绍这些问题&#…

R306指纹识别模块功能实现示例

1 基本通信流程 1.1 UART 命令包的处理过程 1.2 UART 数据包的发送过程 UART 传输数据包前,首先要接收到传输数据包的指令包,做好传输准备后发送成功应答包,最后才开始传输数据包。数据包主要包括:包头、设备地址、包标识、包长…

2024年【浙江省安全员-C证】模拟考试及浙江省安全员-C证证考试

题库来源:安全生产模拟考试一点通公众号小程序 浙江省安全员-C证模拟考试是安全生产模拟考试一点通生成的,浙江省安全员-C证证模拟考试题库是根据浙江省安全员-C证最新版教材汇编出浙江省安全员-C证仿真模拟考试。2024年【浙江省安全员-C证】模拟考试及…

Jenkins持续集成(上篇)

(一)持续集成与 Jenkins 介绍 持续集成 持续集成(Continuous integration,简称 CI),随着近几年的发展,持续集成在项目中得到了广泛的推广和应用。本章将带领读者一起了解持续集成工具 Jenkins…

jdk和IDEA教育版下载和安装详解

前言 研究生专业是通信系统,为了寻找实习于是在研二时期学习java。但是在学习java的过程中没有进行系统总结,很多知识点或者一些细节已经忘记。由于工作找的是某行软件中心的软件开发。准备在毕业前对java知识进行系统性学习。本专栏将从零基础开始,从最简单的jdk和IDEA下载…