网络流算法学习笔记——最大流问题基本概念和Ford-Fulkerson方法(标号法C++实现)

基本概念容量网络:N。连通图N=<V,E,C,s,t>容量:c(i, j)。每条边有一个非负实数c(i, j)代表边的容量发点/源点:s收点/汇:t中间点:除发点、收点外的顶点可行流:f设f:E->R*(非负实数集),满足:容量限制,即f(i, j)<=C(i, j);平衡条件,即对于所有中间点,∑f(i, j) = ∑f(j, i),总流入量=总流出量...
摘要由CSDN通过智能技术生成

屈婉玲《算法设计与分析》第2版第7章网络流算法学习笔记。

基本概念

最大流问题,相当于有从s到t的供水系统,每段路径都有限定流量,除了s、t两地外,每个中间点都不能滞留,从s流入多少,就从t流出多少。求该网络能承载的最大流量。

容量网络:N。连通图N=<V,E,C,s,t>

容量:c(i, j)。每条边有一个非负实数c(i, j)代表边的容量

简单容量网络:边的容量均为1,所有中间点要么入度为1要么出度为1

发点/源点:s

收点/汇:t

中间点:除发点、收点外的顶点

可行流:f。设f:E->R*(非负实数集),f(i, j)表示从i到j的流量。满足:

  1. 容量限制,即f(i, j)<=C(i, j);
  2. 平衡条件,即对于所有中间点,∑f(i, j) = ∑f(j, i),总流入量=总流出量;

则称f是N上的一个可行流。

流量:v(f)。发点s净流出量,记做v(f) = ∑f(s, j) - ∑f(j, s),总流出量-总流入量;收点的净流入量与之相等,即v(f) = ∑f(j, t) - ∑f(t, j)。

最大流:流量最大的可行流。

割集(A, A补)。A是V的子集,且s∈A,t∈A补,称(A, A补)为网络N的割集,
割集就是将N切成分别包含发点和收点的两部分。

容量c(A, Ã)。跨越割集两部分的所有边的容量和,记为(A, Ã) = ∑c(i, j),i∈A,j∈Ã。由于N上的任何可行流都要流过从A流到Ã,所以可行流量(包括最大流)不可能超过割集容量,即:v(f) <= c(A, Ã)。

最小割集:容量最小的割集。

最大流最小割定理:容量网络的最大流的流量,等于最小割的容量。
若v(f) == c(A, Ã),则f是最大流,(A, Ã)是最小割,即当流量等于割的容量时,此流为最大流,此割为最小割。因为割的容量大于等于最大流,一个能把割充满的流量一定是最大流了,此时割到的都是满流的要害路径(其它路径可能还有剩余流量),割到的正好是流量最小的路径,即是最小割。

Ford-Fulkerson方法

求最大流的经典方法,简称FF算法,属于贪心算法。

引入概念

饱和边:网络N中流量 == 容量的边;
非饱和边:网络N中流量 < 容量的边;

零流边:流量 == 0的边
非零流边:流量 > 0的边

i-j链:从顶点i到顶点j的一条边不重复的路径
前向边:与链的方向一致的边
后向边:与链的方向相反的边(后向边相当于是回流的边)
i-j增广链:链中所有前向边非饱和,所有后向边非零流

定理:可行流f是最大流等价于不存在f的s-t增广链。

基本步骤

从给定的初始可行流开始(通常取0流),寻找一条关于当前可行流的s-t增广链P,最大限度修改链上的流量,得到一个新可行流。

重复这个过程,直到找不到s-t增广链为止。

标号法寻找s-t增广链

有时称FF为method而非algorithm,因为它的实现算法可以有多种,寻找s-t增广链可以有多种方式。

屈婉玲《算法设计与分析》第2版教材中使用的是标号法。采用了类似广度优先搜索的方法,又不完全相同。如下面图例中图b,搜索顺序是s,1,2,3(广度优先的话应该是s,1,2,4)。

从s开始搜索,逐个给顶点标号,记录流量来源和流量大小,记为(l, d)。其中l = +i表示流量来源是i且<i, j>是前向边,l = -i表示来源是i且<j, i>是后向边(即是从i回流过来的)。

初始化i=s,标号为(-1, ∞)(从-1流过来的,流量有无穷大)。每一步取一个已标号的节点i,检查所有与之相连且未标号的节点j,找当前所有容量余量中的最小值
若<i, j>是前向边且f(i, j) < c(i, j), 则取d = min{d, c(i, j) - f(i, j)),给j标号(+i, d);(前向边容量剩多少,就还能留多少)
若<j, i>是后向边且f(j, i) > 0, 则取d = min{d, f(j, i)),给j标号(-i, d)。(后向边有多少流量,就最多能回流多少)

得到最小割

当找不到s-t增广链(最后一次循环)时,获得标号的顶点组成A,未获得标号的顶点组成Ã,(A, Ã)即为最小割集。

图例

以图7.2为例,模拟FF算法流程:
在这里插入图片描述
1. 原始容量网络如下:

代码实现

输入:第一行输入节点数N(从0到N-1编号,0为发点,N-1为收点)和边数M;接下来M行,每行给出一条边<i, j>,用i j 容量描述,输入样例如下:
6 9
0 1 8
0 2 12
1 3 6
1 4 10
2 1 2
2 3 10
3 5 8
4 3 2
4 5 10

输出:最大流f(i, j),用i j 流量描述;接下来一行打印发点发出的总流量;接下来两行分别输出最小割集A的顶点,和Ã的顶点。输出样例如下:
Maximum flow:
0 1 8
0 2 10
1 3 0
1 4 10
2 1 2
2 3 8
3 5 8
4 3 0
4 5 10
Total flow:
18
Minimum cut:
0 2 3
1 4 5

#include <iostream>
#include <vector>
#include <climits>
using namespace std;

void BFS(int s, int t, vector<vector<
  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值