网络流(最大流)基础入门

2023-10-31

好不容易大概搞懂了网络流,写个博客巩固一下(盗了点图,请图主原谅)
**

定义 网络流与最大流

**

网络流是指给定一个有向图,和两个点–源点S和汇点T,点之间有连边,
每条边有一个容量限制,可以看作水管,网络流就是指由S点流到T点的一个可行流。
最大流就是指所有可行流里面最大的流。

通俗的讲,就是由若干个运货点,一个是起点,一个是终点,有一些运货点由路相连,每条路有容量限制,走过那条路时运送的货物不能超过其中的容量限制,求最大流就是求从起点运送尽量多的货物到终点,到达终点的货物个数。

举个例子:
这里写图片描述
此时最大流为4。

网络流性质

同时,网络流也有三个性质:
1、容量限制: f[u,v]<=c[u,v]
2、反对称性:f[u,v] = - f[v,u]
3、流量平衡: 对于不是源点也不是汇点的任意结点,流入该结点的流量和等于流出该结点的流量和。
网络流必须满足这三个性质
第一个很容易理解,就是运送的货物不能够超出限制
第二个也很容易理解,v向u流入x,v减少,u增加,如果从反方向看,就意味着
u减少-x,v增加-x,也就是u向v流入-x
第三个就是除了源点和汇点的运货点不能够囤货,收到货物就要发出去。

最大流算法Dinic

最大流的算法有很多,有EK,Dinic,ISAP等
现在就介绍一种时间效率很高的算法–Dinic,
概念

其实EK,Dinic都有一个统一的思路–找增广路,
相信同学们在学二分图的时候已经听过这个名词,

增广路的意思是在当前网络之后找到一条能够从源点到汇点能运更多货物的路径。当一条边被增广之后(即它是增广路的一部分,或者说增广路通过这条边),这条边还能通过的流量,叫做剩余流量,修改之后的图称为残量网络。

拿刚才的作为例子:
这里写图片描述
所以这类算法的思路就是,一直找增广路,找到没有为止
但是如果走完增广路,有更优的流法怎么办?例如说:
这里写图片描述
又图可知,最大流为4,
但在这个图里面,若算法选择了红色路径为增广路,
这里写图片描述
此时流为2,这样走之后就找不到增广路了,因此最大流为2,显然不对。

正确路径应是:
这里写图片描述
所以我们不能够单纯的寻找,需要给程序提供一个反悔的机会,
在这里我们引入一个反向弧的概念,也就是在增广的同时,给增广路上的边的反向边容量增加所增广流量:
这里写图片描述
意思是,程序可以反悔,把所流的流量流回去。
按照这个步骤,继续执行下去,程序就会找到另一条增广路,从而得到正确答案。
这里写图片描述
将原本红色的增广流量流回去到1点,然后换一条路径到-2-T,此时蓝色就可以走4-T增广,其实是一种“偷梁换柱”的手法。
引入反向弧后,就能解决这个问题。

算法步骤

Dinic算法是在找增广路 前提下加了几个优化,

先给一个步骤,后面详细解释:
1.用BFS建立分层图
2.用DFS的方法寻找一条由源点到汇点的路径,获得这条路径的流量x.
根据这条路径修改整个图,将所经之处正向边流量减少x,反向边流量增加x
重复步骤2,直到DFS找不到新的路径时,重复步骤1

1、BFS

为了避免走重复的路径,
首先从S点BFS,将整个图分成若干层,变成层次图,S点为第0层,
定义dis[u]为u所在的层数,也就是至源点的最短距离。
(tips:如果u点到下一个节点v的边剩余容量为0,则算法忽略此边,因为剩余容量为0已经无法增广)

例如说:
这里写图片描述
如果在BFS的时候没有遍历过T点,则说明源点与汇点不连通,函数返回0,算法结束。
有的话,返回1,代表建立成功,那么dis数组可以为接下来的DFS寻找增广路提供优化。

2、DFS

在BFS之后就要从源点开始DFS找增广路,
DFS(u,exp)表示经过u点时当前流量为exp。
刚开始时从源点DFS时,exp=∞,表示从该点流出的流量可以为无限大。
在DFS中遍历u所连接的点v,dis[v]必须等于dis[u]+1,否则会多走没有必要的路径。
可以利用DFS进行多路增广来保证时间效率,即一次增广多条路。

因边有流量限制,所以DFS(u,exp)

[Math Processing Error]
当u点为T时,就等于找到一条由S点到T点的增广路,返回exp至上一层。
当u点不为T时,定义一个值flow为在u点所增广的流量,初始值为0
同时要找下一个节点以DFS(节点是一条以u为起点的边上的终点),
但需要一些限制,首先dis[v]=dis[u]+1,而且该边的剩余容量不能为0,否则肯定不能够增广更多的流量。
对于每次节点的DFS,如果该DFS可以增广的流量为0,说明增广失败,就直接跳过后面,找下一个节点v。
不为0的话,当前exp就减去增广路的流量,代表着在u点还可以流的流量,如果exp已经等于0就代表着在该点已经没有更多流量可以流过去了,必须退出增广。
flow加上该增广路增广流量。
同时,正向边减去流量,代表剩余流量,反向边加上流量(反向弧)

最后,该点所有的节点遍历完后,返回该点所增广的流量flow给上一层。

整个DFS结束后,最大流累加器ans加上S点的增广流量,因为停止了DFS,
所以已经没有路可以增广,所以重新BFS给当前残余网络建层次图。
如果BFS返回0,即S点和T点不联通时,直接退出,输出当前ans,
也就是最大流

即伪代码:

while(BFS()):
ans += DFS(S,inf)

这样,Dinic算法的步骤就结束了。

模拟

让我们来模拟一下吧:
以下面这个图作为例子:
这里写图片描述
首先用BFS分层,层次图如下:
这里写图片描述
分层后开始由S点DFS,
首先DFS(S,∞):
找到下一个节点3,dis[3]=dis[S]+1,所以可以,
此时流进3的最大流量只能是现在走过路径所允许的容量和当前点点流量的最小值,即min(∞,5)=5,即进入DFS(3,5)。

DFS(3,5):
找到下一个节点T,此时流进T最大流量为min(5,3)=3。
所以进入DFS(T,3)

DFS(T,3):
因为走到T,所以找到一条增广路,流量为3,返回增广流量3上一层。

DFS(3,5):
找到一条增广路,所以当前点3还可以流的流量为:5-3=2(留了一些到T点),在该点所增广得到的流量为0+3=3
正向边减3,反向弧加3,也就是:
这里写图片描述
然后从3寻找下一个节点1,由于dis[1]!=dis[3]+1,所以跳过。
接下来没有其他节点了,返回该点所增广流量3到上一层。

DFS(S,∞):
在节点3得到增广流量3,所以当前节点可流流量,∞-3=∞(S点可流无穷的水),在S点增广得到的流量为:0+3=3
同理,正向边减3,反向弧加3,也就是:
这里写图片描述
修改完边之后,遍历S下一个节点1,因为dis[1]=dis[S]+1,所以没有问题,能流进1最大流量:min(∞,5)=5,所以进入DFS(1,5)

DFS(1,5):
找到下一个节点2,dis[2]=dis[1]+1,
能流进2最大流量:min(5,6)=5,所以DFS(2,5)

DFS(2,5):
找到下一个节点T,dis[T]=dis[2]+1,
能流进T最大流量:min(5,10)=5,所以DFS(T,5)

DFS(T,5):
走到T了,直接返回增广流量5给上一层。

DFS(2,5):
flow=0+5=5,该点还可以流的流量为5-5=0,
正向边减5,反向边加5,也就是:
这里写图片描述
返回5到上一层

DFS(1,5):
flow=0+5=5,还可流流量5-5=0,正向边减5,反向边加5,
这里写图片描述
返回5到上一层

DFS(S,∞):
flow=5+3=8,还可流流量∞,正向边减5,反向边加5,
这里写图片描述
因为是源点,且此时已经找不到下一个节点,所以不用回溯,累加器ans加上8。

因为找不到下一条增广路,所以重新BFS分层,分层后如图所示:
(剩余容量为0的边忽略,因为其不能通过任何流量)
这里写图片描述
到这里请某位模拟大神上来模拟一下。
模拟后,你们对算法的过程应该会有更深刻的了解。

反向边的存储和查询

那么,在实际编程中,有什么要注意的?
首先,网络流的边可以用链式前向星存储,你们应该知道,就是:

struct Edge{
int v,w,nxt;
}g[MAXM];
int head[MAXN],cnt;

void addEdge(int u,int v,int w){
g[cnt]=(Edge){v,w,head[u]};
head[u]=cnt;
++cnt;
}

然而反向弧应该怎么存储呢,在dfs过程中addEdge新建边显然是不现实的,
所以可以在建图过程中加了普通边后,把反向边addEdge,容量为0,这样会方便加。
例如:

addEdge(u,v,w);addEdge(v,u,0);

那么如何求一条边的反向边呢,假设那条边的编号为i,那么反向边应为i^1,
例如说u-v编号为3,其反向边v-u编号为3^1=2,
v-u编号为2,其反向边u-v编号为2^1=3。
但要注意的是边的编号要从0开始,否则这种方法无效

模版题

只要理解之后,最大流其实很简单,其实还有很多的优化,
在这里就由于时间关系不讲了,可以课后找我问。
同时也给你们推荐一道模版题 「网络流模板」图图的最大流
可以拿来测你们模版的时间(打满优化才能A)

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
using namespace std;
#define inf 0x7fffffff

struct Edge{
    int v,w,nxt;
}g[1001];
int head[1001];
int cnt;

void addEdge(int u,int v,int w){
    g[cnt].v = v;
    g[cnt].w = w;
    g[cnt].nxt = head[u];
    head[u] = cnt;
    ++ cnt;
}

int n,m,x,y,z;
int ans,flow;
int dis[1001];
queue<int> q;
int S,T;

void init(){
    memset(head,-1,sizeof(head));
    memset(g,0,sizeof(g));
    cnt = 0;
    memset(dis,-1,sizeof(dis));
    while(!q.empty()) q.pop();
    ans = 0;
}

int bfs(){
    memset(dis,-1,sizeof(dis));
    while(!q.empty()) q.pop();
    dis[S] = 0;
    q.push(S);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        for(int i=head[u];i!=-1;i=g[i].nxt){
            int v = g[i].v;
            if(dis[v]==-1 && g[i].w > 0){
                dis[v] = dis[u] + 1;
                q.push(v);
            }
        }
    }
    return dis[T]!=-1;
}

int dfs(int u,int exp){
    if(u==T) return exp;
    int flow=0,tmp= 0;
    for(int i=head[u];i!=-1;i=g[i].nxt){
        int v = g[i].v;
        if((dis[v] == (dis[u]+1)) && (g[i].w>0)){
            tmp = dfs(v,min(exp,g[i].w));
            if(!tmp) continue;

            exp -= tmp;
            flow += tmp;

            g[i].w -= tmp;
            g[i^1].w += tmp;

            if(!exp) break;
        }
    }
    return flow;
}

int main(){
    while(~scanf("%d%d",&m,&n)){
        init();
        S = 1;T = n;
        for(int i=1;i<=m;++i){
            scanf("%d%d%d",&x,&y,&z);
            addEdge(x,y,z);
            addEdge(y,x,0);
        }
        while(bfs()){
            ans += dfs(S,inf);
        }
        printf("%d\n",ans);
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网络流(最大流)基础入门 的相关文章

  • 网络流之最大流和最小割

    最大流问题 最大流 给定有向图中每条边的最大流量 容量 求从源点到汇点的最大流量 容量网络 括号左边代表容量 右边代表流量 残留网络 流网络中剩余可增加的流量 增广路 满足容量条件的一条流量不为零的路径 增广路定理 设容量网络G V E 的
  • 一道模拟赛的题

    前言 这是一个不错的题啊 在这里记录一下 题意 听说不是原创题 那我就放上来了 应该没有关系吧QAQ 有一个 n m 的地图 地图上的每一个位置可以是空地 炮塔或是敌人 你需要操纵炮塔消灭敌人 对于每个炮塔都有一个它可以瞄准的方向 你需要在
  • Reactor Cooling【ZOJ 2314】【无源汇有上下界可行流】

    题目链接 无源汇上下界可行流 没有源点 S 汇点 T 在网络中求可行流或者指出不存在 对于这个问题 不好处理 但是如果我们去掉流量下界限制 B 那么就是最大流的模型了 问题就可以解决了 但是 我们不能直接去掉 因为有可能存在入 出的情况 也
  • [Wc2007]剪刀石头布【竞赛图最大三元环个数+费用流】

    题目链接 BZOJ 2597 给定一个存在不确定边的竞赛图 求原图有向三元环数的最大值 有些边是不确定方向的 我们需要给这些边定向来使得三元环的数目最多 总所周知 由三个点的竞赛图组成的三元环 每个点的入度都应该为1 这样才可以组成一个三元
  • 网络流(最大流)基础入门

    好不容易大概搞懂了网络流 写个博客巩固一下 盗了点图 请图主原谅 定义 网络流与最大流 网络流是指给定一个有向图 和两个点 源点S和汇点T 点之间有连边 每条边有一个容量限制 可以看作水管 网络流就是指由S点流到T点的一个可行流 最大流就是
  • 【SGU 176】 Flow construction

    176 Flow construction time limit per test 0 5 sec memory limit per test 4096 KB input standard output standard You have
  • HS BDC 【HDU - 3472】【混合半欧拉图构建欧拉图+最大流】

    题目链接 有N个字符 如果字符可以首尾相同字符相接组成一条链的话 那么就是说明是well done的 不然 就不是 所以考虑成一条边 我们把每个字符串考虑成有向边 又有些字符串是可以反转的 实际上可以把它当成是无向边来考虑 现在 就是要知道
  • 网络流dinic算法复杂度

    Dinic算法的时间复杂度的理论上界是O N2 M N是结点数 M是边数 但实际上Dinic算法比这个理论上界好得多 如果所有边容量均为1 那么时间复杂度是O min N0 67 M0 5 M 对于二分图最大匹配这样的特殊图 时间复杂度是O
  • Interval【对偶图优化最小割(最大最小定理 周冬)】

    2020牛客多校第二场I题 首先 我们考虑最小割的方式来处理该问题 很明显的 这就是一张对偶图了 因为它没有任意两线会存在相交的可能了 所以根据对偶图的做法 我们可以将最小割问题转化为最短路了 绿色和粉色是新的对偶图所构成的边和点 然后我们
  • 【NOI2018模拟3.26】Cti

    Description 有一个 n m 的地图 地图上的每一个位置可以是空地 炮塔或是敌人 你需要操纵炮塔消灭敌人 对于每个炮塔都有一个它可以瞄准的方向 你需要在它的瞄准方向上确定一个它的攻击位置 当然也可以不进行攻击 一旦一个位置被攻击
  • 动物森友会【科大讯飞杯L题】【二分答案+最大流】

    题目链接 有N个物品 一周有7天 然后呢 要对应的每个物品都要达到各自的需求数量 于是问 最少需要几天才可以达到要求 很明显的 这是线性关系的 我们可以用二分答案来解决这个问题 然后呢怎么知道是否满足条件也就是来确定的 要满足每个物品都要拿
  • 地震逃生【最大流模板题】

    题目链接 P1343 地震逃生 简单的最大流的模板 小心 0 的RE情况 读题 另外 写的是ISAP include
  • [NOI2009]植物大战僵尸【拓扑+最大权闭合子图】

    题目链接 BZOJ 1565 看到这道题之后很容易想到的就是最大权闭合子图了 但是却有个问题就是要去除掉那些环 因为构成了环之后 相当于是无敌的状态 它们就永远不会得到贡献 并且环之后的点也是得不到贡献的 所以 这里利用拓扑 知道哪些点是可
  • 【SDOI2016】数字配对【建立二分图+费用流求方案数】

    题目链接 首先 我们可以看一下这个推导过程 如果 那么 对于 就一定不是质数 一定是它的一个因子 于是可以看出 这一定是一幅二分图 于是 可以根据二分图的性质来确定了每个点的属于S边还是T边了 include
  • PowerOJ 2543: 赛场布置

    题目链接 对于每个点 它可以选择男或者女 如果要加上的贡献 那么相邻的一定得是异性才可以 所以 对相邻的 我们可以考虑成 然后 我们对于点坐标的的奇偶性分别讨论即可 当然 还需要考虑的贡献 然后就是全选减去最少割去的即可 include
  • 【codeforces #290(div 1)】ABC题解

    A Fox And Names time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard o
  • Dinic算法学至大佬,学以致用【挂上相应的题目】

    这个巨佬讲的超级厉害 学起来很快 还有优化的说呢 Dinic算法 研究总结 网络流 网络流是信息学竞赛中的常见类型 笔者刚学习了最大流Dinic算法 简单记录一下 网络流基本概念 什么是网络流 在一个有向图上选择一个源点 一个汇点 每一条边
  • Binary Tree on Plane【费用流】

    题目链接 CF 277 E 题意翻译 给你平面上 n 个点 2 n 400 要求用这些点组成一个二叉树 每个节点的儿子节点不超过两个 定义每条边的权值为两个点之间的欧几里得距离 求一个权值和最小的二叉树 并输出这个权值 其中 点 i 可以成
  • AtCoder Beginner Contest 332 G. Not Too Many Balls(最大流转最小割 dp)

    题目 n n lt 500 种球 第i种有ai 0 lt ai lt 1e12 个球 m m lt 5e5 个盒子 第j个能放bj 0 lt bj lt 1e12 个球 特别地 第j个盒子最多能放i j个第i种球 求m个盒子能放的最多的球的
  • 坐标前后限制转点的坐标取值+网络流拆维拆点:agc031_e

    https vj imken moe contest 598718 problem J 观察到数据范围很小 但一个很重要的信息我们缺失了 就是珠宝的数量 所以我们考虑枚举珠宝的数量 k k k 对于横纵坐标什么至多至少的限制 比如 a i

随机推荐

  • git add 命令详解

    1 前言 2 git add 基本操作 3 git add 命令参数 4 git add 背后做了什么 1 前言 众所周知 git 中有工作区 暂存区 版本库三大组成部分 工作区 电脑中能看到的目录 也就是写代码的地方 暂存区 英文叫 st
  • vue3中通过自定义指令,实现点击空白处触发事件,点击非自身dom触发事件

    我们经常在开发过程中 会遇到这些问题 怎么实现点击空白处关闭指定盒子 怎么实现点击空白处收起下拉框 即 怎么触发点击空白处事件 怎么触发 点击非自身dom而触发的事件 在vue3当中 使用自定义指令解决这个问题 在utils directi
  • 开启network-manager.service

    ubuntu20 04 本身系统会默认开机自动连接网络服务 但是我之前自己设置关闭了 所以现在要手动打开使用一下命令 先进入root xxz sudo systemctl start network manager service 回车执行
  • 《一》HI3518E视频处理基础知识----- 系统控制mpp

    目录 一 MPP的概述 1 视频方面 2 音频方面 3 MPP所处层次框架图 二 mpp处理平台架构 三 视频缓存池 1 视频缓冲池 VB 2 要点 3 相关的数据结构和API 1 VB CONF S 2 HI MPI VB SetConf
  • 家谱(特殊的层级人物关系)数据结构与自动排版算法的一种实现

    github源代码 家谱海本地私有版 https github com fengchangfight familytreesea 出处 http www fengchang cc post 24 家谱的数据结构并不复杂 逻辑上可以抽象成一种
  • BES2300x笔记(28) -- 左右耳同时按下的骚操作

    哈喽大家好 这是该系列博文的第二十八篇 篇 lt lt 系列博文索引 快速通道 gt gt 一 前言 市面上的TWS耳机 一般中高端耳机都会有触摸按键和入耳检测功能 使用触摸按键更方便外观和防水处理 但同时也限制了UI交互方式 有限的交互方
  • eclipse快速打开和闭合函数方法代码块的快捷方式

    ctrl shift 小键盘 收起和ctrl shift 小键盘 闭合
  • 基于深度学习的变化检测算法实现

    我是研究生期间研究主要研究SAR影像的变化检测 这是一段简单的基于深度学习的变化检测方法 以CNN实现 首先说下基于深度学习的变化检测任务的思路 制作训练样本 gt 训练模型 gt 使用训练的模型遍历图片中每个像元得出结果 1 筛选训练样本
  • spring.ftl

    lt ftl strip whitespace true gt lt spring ftl This file consists of a collection of FreeMarker macros aimed at easing so
  • css中垂直对齐常用的几种方法

    一 行高 line height 法 如果要垂直居中的只有一行或几个文字 那它的制作最为简单 只要让文字的行高和容器的高度相同即可 比如 p height 30px line height 30px width 100px overflow
  • Angularjs理解二

    1 dom加载完毕 找寻ng app 先从上到下找相关的指令 然后分两阶段执行 先找到所有的指令 完成编译 得到一个个链接函数 最后在链接到一个个controller上 还是边编译边链接 先执行 injector invoke rootSc
  • 光耦PC817

    光耦一共4个引脚 两个输入 两个输出 输入接5v和gnd 5v接时加100欧姆电阻 输出不大于35v电压 这时输出端通路 只是通路 不是短路 转载于 https www cnblogs com judes p 5686414 html
  • PCA主成分分析(入门计算+深入解析)(一)

    PCA主成分分析 入门 深入 最大方差理论 几何意义 Principal components analysis 转载请注明 云南省高校数据化运营管理工程研究中心博客http blog csdn net m0 37788308 articl
  • Python解决相对路径问题

    学习Python中 一直被相对路径困扰 只能使用绝对路径 解决方法 加上下面代码 import os sys os chdir sys path 0 这个问题到现在也没有搞清楚 因为在命令行直接敲命令运行py文件可以直接使用相对路径 而我在
  • 浅谈三目运算符(c++)

    目录 什么是三目运算符 三目运算符怎么用 基本用法 进阶用法 注意事项 相关题目 B2035 判断数正负 B2037 奇偶数判断 B2052 简单计算器 什么是三目运算符 三目运算符是分支结构中的一种运算 根据不同的条件 执行不同的操作并返
  • win10家庭版解决无法进入本地组策略编辑器问题

    win10家庭版无法进入本地组策略编辑器 现象 运行框中输入 gpedit msc 提示 Windows找不到文件gpedit msc 解决办法 一 桌面新建一个文本文档 输入以下代码后保存文档 echo off pushd dp0 dir
  • 【华为OD机试真题 Python】最优高铁城市修建方案(200分)

    前言 本专栏将持续更新互联网大厂机试真题 并进行详细的分析与解答 包含完整的代码实现 希望可以帮助到正在努力的你 关于大厂机试流程 面经 面试指导等 如有任何疑问 欢迎联系我 wechat steven moda email nansun0
  • python读取Java配置文件properties配置文件

    python没有专门处理properties格式的包 只有处理标准的ini格式的包 所以需要自己写一个python程序来处理 class Properties object def init self fileName self fileN
  • Hugging Face 的 Transformers 库快速入门 (一)开箱即用的 pipelines

    注 本系列教程仅供学习使用 由原作者授权 均转载自小昇的博客 文章目录 前言 开箱即用的 pipelines 情感分析 零训练样本分类 文本生成 遮盖词填充 命名实体识别 自动问答 自动摘要 这些 pipeline 背后做了什么 使用分词器
  • 网络流(最大流)基础入门

    好不容易大概搞懂了网络流 写个博客巩固一下 盗了点图 请图主原谅 定义 网络流与最大流 网络流是指给定一个有向图 和两个点 源点S和汇点T 点之间有连边 每条边有一个容量限制 可以看作水管 网络流就是指由S点流到T点的一个可行流 最大流就是