当前位置: 首页 > news >正文

39.网络流入门

1 基本知识

1.1 问题简介

在生活中,许多系统都包含了流量这一概念,例如:自来水系统的水流、财务系统的现金流、互联网中的信息流等等。而他们都包含通道、流量、流速、上限等性质,因此我们通常将关于它们的问题抽象成图论的形式。

网络流就是在图论中用来解决相关问题的一个适用范围相当广的模型,相关的算法也非常多。尽管如此,网络流中的概念、思想和基本算法并不难理解。在本节我们将介绍一些基本的内容和算法,作为网络流问题的引入。

1.2 抽象形式

网络 G=(V,E)G=(V,E)G=(V,E) 是指一种特殊的有向图,在具备基本的有向图特性之外,其最大不同在于有容量源汇点

  • EEE 的每条有向边 (u,v)∈E(u,v)\in E(u,v)E 都有一个被称为容量的权值 c(u,v)c(u, v)c(u,v)。若 (u,v)∉E(u,v)\notin E(u,v)/E,假定 c(u,v)=0c(u,v)=0c(u,v)=0 可不失一般性;
  • VVV 中有两个特殊的点 S,T∈VS,T\in VS,TV:源点 SSS 和汇点 VVVS≠TS\neq TS=T
  • 有时候我们还会给定一个单位费用 w(u,v)w(u,v)w(u,v),当边 (u,v)(u,v)(u,v) 的流量为 f(u,v)f(u,v)f(u,v) 时,它的花费即为 f(u,v)w(u,v)f(u,v)w(u,v)f(u,v)w(u,v)

对于网络 GGG,我们定义一个流函数 f(u,v)f(u,v)f(u,v),它表示一个从边集 EEE 到整数集或实数集的函数,它具有以下性质。

  • 容量与流量:对于每条边,流经该边的流量不得超过该边的容量,即 f(u,v)≤c(u,v)f(u,v) \leq c(u,v)f(u,v)c(u,v)
  • 流量守恒:除源汇点外,任意结点 xxx 的流入与流出相同,即 ∀x≠S,T,∑(u,x)∈Ef(u,x)=∑(x,v)∈Ef(x,v)\forall x\neq S,T,\sum_{(u,x)\in E}f(u,x)=\sum_{(x,v)\in E}f(x,v)x=S,T,(u,x)Ef(u,x)=(x,v)Ef(x,v)

此外我们定义 f(u,v)=−f(v,u)f(u,v)=-f(v,u)f(u,v)=f(v,u) 来表示一个反向边的负流量,这个定义在具体的算法中有很大的作用。

给定一个网络 G=(V,E)G=(V,E)G=(V,E),设源点汇点分别为 S,TS,TS,T,若一个边集 E′⊆EE'\subseteq EEE 被删去后,S,TS,TS,T 不在连通,则我们称该边集 E′E'E 为网络的

1.3 常见问题类型

常见的网络流问题包括但不限于以下类型问题。

  • 最大流问题:对于网络 G=(V,E)G=(V,E)G=(V,E),给每条边指定流量,得到合适的流 fff,使得 fff 的流量尽可能大。此时我们称 fffGGG 的最大流。我们还可以用最大流的方式求解二分图匹配问题。
  • 最小割问题:对于网络 G=(V,E)G=(V, E)G=(V,E),找到合适的割 E′E'E,使得 E′E'E 的总容量尽可能小。此时我们称 E′E'E 的总容量是 GGG 的最小割。
  • 最小费用最大流问题:对于网络 G=(V,E)G=(V,E)G=(V,E),对于 GGG 所有可能的最大流,我们称其中总费用最小的一种为最小费用最大流。

2 最大流问题

2.1 增广路

对于边 (u,v)(u,v)(u,v),我们将其容量与流量之差称为剩余容量 cf(u,v)c_f(u,v)cf(u,v),即 cf(u,v)=c(u,v)−f(u,v)c_f(u,v)=c(u,v)-f(u,v)cf(u,v)=c(u,v)f(u,v)

我们将 G(V,E)G(V,E)G(V,E) 中所有结点和剩余容量大于 000 的边构成的子图称为残量网络 Gf(V,Ef)G_f(V,E_f)Gf(V,Ef),其中 Ef={(u,v)∣cf(u,v)>0}E_f=\left\{(u,v) \mid c_f(u,v)>0\right\}Ef={(u,v)cf(u,v)>0}

我们将 GfG_fGf上一条从源点 SSS 到汇点 TTT 的路径称为增广路。对于一条增广路,我们给每一条边 (u,v)(u, v)(u,v) 都加上等量的流量,以令整个网络的流量增加,这一过程被称为增广。我们可以知道,当增广路不存在时,当前的流即为最大流。由此,最大流的求解可以被视为若干次增广分别得到的流的叠加。

2.2 Edmonds-Karp 算法

利用增广路寻找最大流的最简单方法就是 Edmonds-Karp 算法,核心思想就是不断使用 BFS 来寻找增广路,直到网络中不存在增广路为止。

特别注意,当 f(u,v)>0f(u,v)>0f(u,v)>0 时,我们有 f(v,u)<0<c(y,x)f(v,u)<0<c(y,x)f(v,u)<0<c(y,x)。因此我们在 EK 算法中需要考虑到它的反向边,此时反向流量的用意即为减少之前的流量。

void bfs()
{queue<ll> q;q.push(S);memset(pre, -1, sizeof(pre));while(!q.empty()){ll u = q.front();q.pop();for(ll i = p[u]; i != -1; i = e[i].next){ll v = e[i].v, c = e[i].c;if(pre[v] == -1 && c > 0){pre[v] = i;q.push(v);if(v == T)return;}}}
}
ll EK()
{ll ret = 0;while(1){bfs();if(pre[T] == -1)break;ll Min = inf;for(ll u = T; u != S; u = e[pre[u]].u)Min = min(Min, e[pre[u]].c);for(ll u = T; u != S; u = e[pre[u]].u){e[pre[u]].c -= Min;e[pre[u] ^ 1].c += Min;}ret += Min;}return ret;
}

EK 算法的时间复杂度较高,可以计算得知为 O(nm2)O(nm^2)O(nm2)。然而在实际应用中效率往往更高,大概能处理规模为 103∼10410^3\sim10^4103104 的网络。

2.3 Dinic 算法

从上面 EK 算法的流程中我们不难发现,EK 算法每次都会遍历整个残量网络,但是最终都只会找出一条增广路,这样的效率很低。因此 Dinic 算法就是在寻找增广路的问题上进行了优化。

我们设 d[x]d[x]d[x] 表示节点的层级,即源点 SSSxxx 的最少边数,我们可以根据层级构造分层图。我们在 Dinic 算法中,只会考虑低层级结点流向高层级结点的情况,因此减少了回流情况。而在 Dinic 算法中,我们一次可以找到多条增广路,因此大大提高了效率。

Dinic 算法重复以下步骤,直到残量网络中 SSSTTT 不连通:

  • 在残量网络中按 BFS 求出结点层级,构造分层图;
  • 在分层图上 DFS 寻找增广路,在回溯时实时更新残量网络。因为每个点可以延伸出多条出边,因此一次 DFS 即可找到多条增广路,提高了算法效率。
bool bfs()
{memset(d, -1, sizeof(d));d[S] = 1;queue<ll> q;q.push(S);while(!q.empty()){ll u = q.front();q.pop();for(ll i = p[u]; i != -1; i = e[i].next){ll v = e[i].v, c = e[i].c;if(d[v] == -1 && c > 0){d[v] = d[u] + 1;q.push(v);if(v == T)return true;}}}return false;
}
ll dfs(ll u, ll flow)
{if(u == T)return flow;ll res = 0;for(ll i = p[u]; i != -1; i = e[i].next){ll v = e[i].v;if(d[u] + 1 == d[v] && e[i].c > 0){ll tmp = dfs(v, min(flow, e[i].c));if(!tmp)d[v] = 0;flow -= tmp;e[i].c -= tmp;e[i ^ 1].c += tmp;res += tmp;if(flow == 0)break;}}return res;
}
void Dinic()
{ll ans = 0;while(bfs())ans += dfs(S, inf);printf("%lld\n", ans);
}

最终算法的时间复杂度为 O(n2m)O(n^2m)O(n2m)。然而在实际应用中效率往往更高,大概能处理规模为 104∼10510^4\sim10^5104105 的网络。而 Dinic 算法求解二分图匹配问题的时间复杂度为 O(mn)O(m\sqrt n)O(mn)

5 作业

P3376 【模板】网络最大流


文章转载自:

http://Xmm2kVbB.yxkyL.cn
http://szYy480c.yxkyL.cn
http://xSPHfTV1.yxkyL.cn
http://YxgAghDY.yxkyL.cn
http://5oubJgTZ.yxkyL.cn
http://3dxWKI3Q.yxkyL.cn
http://YqaTjqk1.yxkyL.cn
http://oNonbfow.yxkyL.cn
http://wJQwDMlN.yxkyL.cn
http://4FrrJGv2.yxkyL.cn
http://n1MBHJNb.yxkyL.cn
http://ZVYEQwgq.yxkyL.cn
http://PWZtqDsv.yxkyL.cn
http://cqpH3mO1.yxkyL.cn
http://qIPQLbKV.yxkyL.cn
http://IS671lsn.yxkyL.cn
http://b8BNA9PB.yxkyL.cn
http://MelH1zPF.yxkyL.cn
http://RHjtvGIJ.yxkyL.cn
http://Z076XOMl.yxkyL.cn
http://X09RnYwF.yxkyL.cn
http://YNOLC8QD.yxkyL.cn
http://55KPc5RA.yxkyL.cn
http://8x9nXxdZ.yxkyL.cn
http://JoAcgshd.yxkyL.cn
http://u80gvpCI.yxkyL.cn
http://G9wfPvfP.yxkyL.cn
http://Cr5ZHO0e.yxkyL.cn
http://lBEZiYZ8.yxkyL.cn
http://uYd1qM81.yxkyL.cn
http://www.dtcms.com/a/382139.html

相关文章:

  • PTQ 模型 量化方法
  • 基于Spring Boot的家政服务管理系统+论文示例参考
  • uniapp封装长按一直触发事件和松开后触发一次的事件(自定义事件)
  • Unity核心概念⑦:Transform
  • 【数据行业发展】可信数据空间~数据价值的新型基础设施
  • 使用“洋葱架构”构建单体应用
  • DAY 27 函数专题2:装饰器-2025.9.14
  • 浅析Linux进程信号处理机制:基本原理及应用
  • php学习(第五天)
  • C盘清理技巧分享的技术文章大纲
  • PINN物理信息神经网络驱动的三维声波波动方程求解MATLAB代码
  • 深度学习优化器进化史:从SGD到AdamW的原理与选择
  • 计算机视觉(opencv)实战十九——角点检测图像特征(Harris 角点、Shi-Tomasi 角点)
  • 【限流器设计】固定窗口计数法
  • Estimator and Confidence interval
  • 构建AI智能体:三十二、LangChain智能体:打造会使用工具(Tools)、有记忆(Memory)的AI助手
  • AI内容标识新规实施后,大厂AI用户协议有何变化?(六)科大讯飞
  • 机械应答到自然交流,声网AI陪练改变我的口语
  • 贪心算法应用:信用评分分箱问题详解
  • 【Spring AI】Filter 简单使用
  • html各种常用标签
  • Linux 进程信号之信号的捕捉
  • 实验-高级acl(简单)
  • C++之特殊类设计
  • stm32教程:USART串口通信
  • 地级市绿色创新、碳排放与环境规制数据
  • ES——(二)基本语法
  • 中级统计师-统计法规-第十一章 统计法律责任
  • 拥抱直觉与创造力:走进VibeCoding的新世界
  • Python进程和线程——多进程