【算法】08 最大流

本文深入探讨了最大流问题,包括网络流的定义、残存网络、增广路径、Ford-Fulkerson算法以及Edmonds-Karp算法。通过实例解释了如何在残存网络中寻找增广路径来增加流,并介绍了二分图的最大匹配及其增广路径方法,如匈牙利算法。

最大流

问题:在一个流网络里,每条边都有运载能力限制,我最多能从源头运输多少数量到目的地?

网络流

定义

G=(V,E)是一个有向图,其中每条边(u,v)有一个非负的容量值c(u,v),而且如果E中包含一条边(u,v),那么图中就不存在它的反向边。在流网络中有两个特殊的结点,源结点s和汇点t。

下面给出流网络的形式化定义。令G=(V,E)为一个流网络,其容量函数为c,设s我为网络的源点,t为汇点。G中的流是一个实值函数f,满足以下两条性质:

  1. 容量限制(capacity contraint):对于所有的结点u,v,要求

  2. 流量守恒(flow conservation):对于所有的非源点和汇点的结点u,要求:

如下为一个流网络示意图:

残存网络

假定有一个流网络G =(V,E),其源点为s,汇点为t,f为G中的一个流。对即诶点对u,v,定义残存容量(residual capacity),有:

残存网络可能包含图G中不存在的边,残存网络中的反向边允许算法将已经发送出来的流量发送回去。一个残存网络示例图如下:

图a是一个流网络,b是a对应的残存网络,将权重为0的边省略。

残存网络是如何增大原始流网络中的流的一种指示。如果f是G的一个流,对应的有一个残存网络,残存网络中我们可以定义一个流f’。定义函数f↑f‘,我们将其称作流f’对f的增量(augmentation)。其值 = 流量 + 残存容量 - 反向残存容量。

增广路径

给定流网络G和流f,增广路径p是残存网络中一条从源结点s到汇点t的简单路径。根据残存网络的定义,对于一条增广路径上的边(u,v),我们可以增加其流量的幅度最大为,即我们之前定义的残存容量(residual capacity)。

最大流最小分割
  1. 割:是一种点的划分方式,对于一个网络流图 G=(V,E),设 E’ ⊆ E,若将 E’ 在 G 中删除后,使得图 G 不在连通,则称 E’ 是图 G 的割。割将所有的点划分为 S 和 T=V-S 两部分,记作:(S,T)

  2. s-t 割:如果割所划分的两个子集使得源点 s∈S,汇点 t∈T,则该割称为 s-t 割,其中弧<u,v>|u∈S,v∈T 称为割的前向弧,弧 <u,v>| u∈T,v∈S 称为割的反向弧。

  3. 割的容量:所有前向弧的容量和,即起点在 S 终点在 T 中的所有边的容量和,记作:c(S,T) = Σc(u,v) | u∈S,v∈T

  4. 最小割:容量网络的最小割即容量最小的割。

  5. 净流量:对于一个割 (S,T),用净流量来表示穿过割 (S,T) 的流量之和,即:|f| = f(S,T) = Σf(u,v) | u∈S,v∈T

Ford-Fulkerson算法

Ford-Fulkerson算法就是在残存网络中不断找增广路径,并将增广路径纳入到结果中;重复这个过程直到无法再找到增广路径位置。

伪代码

#include<stdio.h>
#include<stdlib.h>
#include<vector>
#include<algorithm>
 
#define MAXVEX 100
#define INF 65535
 
//用于表示边的结构体
struct edge
{
   
   
	int to;//终点
	int cap;//容量
	int rev;//反向边
};
std::vector<edge>G[MAXVEX];//图的邻接表表示
bool used[MAXVEX];//DFS中用到的访问标记
 
//向图中增加一条从s到t容量为cap的边
void addEdge(int from, int to, int cap)
{
   
   
	edge e;
	e.cap = cap;e.to = to;e.rev = G[to].size();
	G[from].push_back(e);
	e.to = from; e.cap = 0; e.rev = G[from].size() - 1;
	G[to].push_back(e);
}
 
//通过DFS寻找增广路
int dfs(int v, int t, int f)
{
   
   
	if (v == t)return f;
	used[v] = true;
	for (int i = 0; i < G[v].size(); ++i)
	{
   
   
		edge &e = G[v][i];
		if (!used[e.to] && e.cap > 0)
		{
   
   
			int d = dfs(e.to, t, std::min(f, e.cap)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值