众所周知,网络流是探究网络上运输的一种图论分支。但是大多数人在第一次接触这个题时都有些畏惧感(比如说我),大佬可以自信跳过..


本文包括:

1.网络流的概念及基本性质

2.略谈 Edmonds-Karp增广路算法

3.详谈 Dinic 算法

4.网络流的应用以及ISAP算法引入


1 . 网络流的概念及基本性质

网络流是图论的一种重要分支,我们可以将网络流初步理解为一种 水道 一样的网络。

基本定义: (部分参考《算法竞赛进阶指南》)

对于一个网络 G = (V , E )G=(V,E) 为一张有向图,图中的每条有向边 ( X,Y)∉E(X,Y)∉E , 则 C(X,Y) = 0C(X,Y)=0 。图中还有两个节点 S , TS,T 十分特殊,我们将其称为 源点 和 汇点 。

我们将 ff 函数称作网络的流函数。

对于 (X,Y)∈E , f(X,Y)(X,Y)∈E,f(X,Y) 称为边的流量 , C(X,Y) - f(X,Y)C(X,Y)−f(X,Y) 称为边的剩余流量。

知道大佬们都不想看, 那么直接一点。

假设有一片有向的水域,有多条有向的河流,河流都从 SS 点出发,最终都汇向 TT 点。每条河流有一定的宽度,只允许最多不超过该条河流边权值 的水流通过。

如上图 ,蓝点为源点 , 红点为汇点。而紫色点和紫色边显然无用,选择不流过紫色。

默认 S 点的水量有无限多。

在初步了解后,按照流函数的定义,一个网络中的每条边实际上都有一条反向边,并且这些反向边都有一个负的流量, 这个定义将有助于我们解决之后的回溯问题。

基本性质:

1.容量限制

任意一条边的流量必定小于它的容量(及它的边权)。

2.斜对称定理

一条边 (X,Y)(X,Y) 中 XX 到 YY 的流量必定与其反边 (Y,X)(Y,X) 中 YY 到 XX 的流量相反。

3.流量守恒定理

除了源点 SS 和 汇点 TT 外 ,任意节点的 流入总量 都等于 流出总量 。即不会存储流量 。


2.略谈 Edmonds-Karp增广路算法

学习过匈牙利算法的同学已经了解增广路的定义,没有的话建议先 AA 掉P3386 【模板】二分图匹配 ,将有利于理解本文(貌似没有关联)。

但是增广路此时的定义为:

一条增广路从源点 SS 到汇点 TT 的路径上各边的剩余流量的最小值大于 0 。

而Edmonds-Karp增广路算法(下列简称EK算法)的思路就是对该网络进行BFS,不断找出其增广路,直至将该网络上的所有增广路全部找出。

EK算法的正确性显然,在这里就不给出详细证明。(有兴趣者可参考《算法竞赛进阶指南》)。

EK算法具体实现过程如下:

1 . 用BFS在网络上寻找可行增广路。

2 . 在BFS找到任意一条增广路时计算出该增广路上各边剩余流量的最小值 min 。

3 . 最大流 maxflowmaxflow 的值增加 min ,如此往复直至BFS找不增广路。

给出图 及 图的最大流 7 作参考

代码暂未上传。

但是EK算法存在明显的局限性,及每次更新都要从头到尾BFS一下,只能解决 O(nm^2)O(nm2) 的网络。

于是我们又有下面这个经一步优化的算法。


3.详谈 Dinic 算法

之所以详谈Dinic算法,是因为Dinic算法是代码较简单,较容易实现并且效率极高的网络流算法之一,它对于普通的网络图,处理范围可以达到 10^4 - 10^5104−105 。而相比之下,EK算法仅有 10^3 - 10^4103−104 的处理范围。

并且某位大师推演出Dinic算法在二分图中的复杂度仅有 m \sqrt{n}mn​ , 所以可以在二分图中愉快地跑网络流 啦。上一道例题P1129 [ZJOI2007]矩阵游戏,熟练后可以切了它。

我们先介绍一下Dinic算法的核心之一:残量网。

残量网是指在当前网络中的所有节点以及 剩余容量大于 00 的边构成的子图。

但是有了残量网还不够,要精准判断残量网上两点 X,YX,Y 的关系,即判断它们是否有环之类神奇的边,我们还要借助满足 d[y] = d[x] + 1d[y]=d[x]+1 的分层图。

Dinic算法思路:

1 . 开一个队列, 在残量网中BFS一次,按照遍历层数为每个点表上层次 d[ x ]d[x] ,构造分层图并且判断能否从源点 SS到达汇点 TT 。如果失败则说明残量网无法到达汇点。

2 . 在构造好的残量网上DFS寻找增广路并且,更新边及反边,(否则DFS无法后悔)。

3 . 不断重复 1 2 步骤直至构造的残量网无法到达汇点。

实践是检验真理的唯一标准

模板题P3376 【模板】网络最大流

AC 代码及讲解:

#include<bits/stdc++.h>
using namespace std; const int inf = 0x3f3f3f3 , N = + ; int head[ N* ], d[ N ] , to[ N** ] , w[ N** ] , next[ N** ] ; int n , m , s, t , tot = , maxflow = ;//maxflow记录答案 inline int read()
{
int s = ,w = ;
char g = getchar();
while(g<''||g>''){if(g=='-')w*=-;g = getchar();}
while(g>=''&&g<=''){s = s*+g-'';g = getchar();}
return s*w;
} queue<int> q ;//广搜时采用队列 void add( int x , int y , int z ){
tot++; to[ tot ] = y , w[ tot ] = z , next[ tot ] = head[ x ] , head[ x ] = tot;
tot++; to[ tot ] = x , w[ tot ] = , next[ tot ] = head[ y ] , head[ y ] = tot;
}//建立边和反向边,注意反向边的流量初始为 0 bool bfs(){//在残量网络上构造分层图
memset( d , , sizeof(d) ) ; //将之前的分层清0,继续跑残量网络找可行增广路
while( q.size() ) q.pop() ; //队列清 0 ;
q.push( s ) ; d[ s ] = ; //将源点加入队列,层数为 1 ,开始广搜
while( q.size() ){
int x = q.front() ; q.pop() ;
for( int i = head[ x ] ; i ; i = next[ i ])
if( w[ i ] && !d[ to[i] ] ){//目标边的流量不为0 且 为被遍历分层
q.push( to[ i ] ) ;
d[ to [ i ] ] = d[ x ] + ;
if( to[ i ] == t )return ; //找到一条可行增广路
}
}
return ;//未找到,不存在增广路
} int dinic( int x , int flow ){ //在分层图上进行增广
if( x == t )return flow ;//源点即使汇点,流量不限量
int rest = flow , k ;
for( int i = head[ x ] ; i && rest ; i = next[ i ] )//当前可流入最大流量不为0 ,
if( w[ i ] && d[ to [ i ] ] == d[ x ] + ){//目标路径有剩余流量,且不存在环之类神奇的东西
k = dinic( to[ i ] , min( rest , w[ i ] ) );//继续搜
if( !k )d[ to [ i ] ] = ; //剪枝,如果 k(下一层可流入流量图为 0 ),cut
w[ i ] -= k ;
w[ i ^ ] += k ;//占用k流量,注意反边要加上k,不然无法退回
rest -= k ; //当前节点的剩余汇入流量-k;
}
return flow - rest ; //递归完成
} int main()
{
n = read() ; m = read() ; s = read() ; t = read() ;
for( int i = ; i <= m ; ++i ){
int x = read() , y = read() , L = read() ;
add( x , y , L ) ;
}
int flow = ;
while( bfs() ){//存在增广路
while( flow = dinic ( s , inf ))maxflow += flow ;
}
printf("%d",maxflow) ;
return ;
}

Dinic算法一定要手敲一遍板子,不然你连错在哪都查不出来(除了机对)。


4.网络流的应用以及ISAP算法引入

ISAP算法是EK算法的另一类优化, ISAP算法只需一次BFS即可,但代码难度远远高于Dinic算法。

ISAP算法复杂度在非二分图上高于Dinic算法,在二分图则不如Dinic算法。

在此暂时不详讲,日后会更新ISAP算法详解。

网络流的应用

网络流应用较广, 但建议新手按以下顺序A题,熟练算法和增强应用能力。

网络流的应用

网络流应用较广, 但建议新手按以下顺序A题,熟练算法和增强应用能力。

P3376 【模板】网络最大流

U60438 及川奈砂的蛋糕

P1129 [ZJOI2007]矩阵游戏

P2891 [USACO07OPEN]吃饭Dining

感谢ssw大佬!!

网络流学习(转载自ssw 的博客)的更多相关文章

  1. 【转载】国内网站博客数据统计选免费Google Analytics还是百度统计

    [转载]国内网站博客数据统计选免费Google Analytics还是百度统计 Google Analytics谷歌统计是我用的第一个网站统计工具,当然现在也一直在用.Google Analytics ...

  2. React初步学习-利用React构建个人博客

    React初步学习-利用React构建个人博客 用React和Webpack写了一个很简单的个人博客,主要是想要熟悉一下react中各种基本基本属性及方法的使用.在构建过程中碰到不少问题,通过阅读官方 ...

  3. 转载来自朱小厮博客的 一文看懂Kafka消息格式的演变

    转载来自朱小厮博客的 一文看懂Kafka消息格式的演变     ✎摘要 对于一个成熟的消息中间件而言,消息格式不仅关系到功能维度的扩展,还牵涉到性能维度的优化.随着Kafka的迅猛发展,其消息格式也在 ...

  4. 如何快速转载CSDN中的博客

    看到一篇<如何快速转载CSDN中的博客>,介绍通过检查元素→复制html来实现快速转载博客的方法.不过,不知道是我没有领会其精神还是其他原因,测试结果为失败.

  5. Trie树(c++实现)——转载自jihite的博客

    Trie树(c++实现)   原理 先看个例子,存储字符串abc.ab.abm.abcde.pm可以利用以下方式存储 上边就是Trie树的基本原理:利用字串的公共前缀来节省存储空间,最大限度的减少无谓 ...

  6. JavaScript资源大全中文版(Awesome最新版--转载自张果老师博客)

    JavaScript资源大全中文版(Awesome最新版)   目录 前端MVC 框架和库 包管理器 加载器 打包工具 测试框架 框架 断言 覆盖率 运行器 QA 工具 基于 Node 的 CMS 框 ...

  7. 学习Python不得不关注和学习的国外大神博客

    注意 : 本文收集于网路 . 由于常常更新 , 有些链接打不开, 请自备梯子 在学习Python过程中,总会遇到各种各样的坑, 虽然Python是一门优美而简单易学的语言 . 但当学习后 , 总想着更 ...

  8. [转]如何快速转载CSDN中的博客

    原文:https://blog.csdn.net/bolu1234/article/details/51867099 前言   对于喜欢逛CSDN的人来说,看别人的博客确实能够对自己有不小的提高,有时 ...

  9. iOS开发学习之大牛们的博客

    http://blog.csdn.net/iosbird/article/details/51981023 唐巧:http://blog.devtang.com/blog/archives/ 王巍:h ...

随机推荐

  1. Sublime Text 3下载安装以及安装HTML-CSS-JS Prettify代码格式化插件

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 Sublime Text的安装以及安装插件步骤. 下载Sublime Text 官网地址:http://www.sublimetex ...

  2. ES 09 - 定制Elasticsearch的分词器 (自定义分词策略)

    目录 1 索引的分析 1.1 分析器的组成 1.2 倒排索引的核心原理-normalization 2 ES的默认分词器 3 修改分词器 4 定制分词器 4.1 向索引中添加自定义的分词器 4.2 测 ...

  3. Devexpress常见问题

    1.DevExpress控件组中的GridControl控件不能使横向滚动条有效. 现象:控件中的好多列都挤在一起,列宽都变的很小,根本无法正常浏览控件单元格中的内容. 解决:gridView1.Op ...

  4. DotNetCore跨平台~聊聊中间件

    回到目录 在进行.net core平台之后,我们如果希望在请求过程中添加一些事件是非常容易的,你可以把这些事件做成一个中间件Middleware,然后这些中间件就会以Http pipeline的管道方 ...

  5. Java进阶篇设计模式之三 ----- 建造者模式和原型模式

    前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...

  6. 学习ASP.NET Core Razor 编程系列十五——文件上传功能(三)

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  7. 深入Go的底层,带你走近一群有追求的人

    目录 缘起 自我介绍的技巧 硬核知识点 什么是plan9汇编 汇编角度看函数调用及返回过程 汇编角度看slice 正确参与Go夜读活动的方式 阅读原文 上周六晚上,我参加了"Go夜读&quo ...

  8. [深度概念]·K-Fold 交叉验证 (Cross-Validation)的理解与应用

    K-Fold 交叉验证 (Cross-Validation)的理解与应用 我的网站 1.K-Fold 交叉验证概念 在机器学习建模过程中,通行的做法通常是将数据分为训练集和测试集.测试集是与训练独立的 ...

  9. Flink-Kafka-Connector Flink结合Kafka实战

    戳更多文章: 1-Flink入门 2-本地环境搭建&构建第一个Flink应用 3-DataSet API 4-DataSteam API 5-集群部署 6-分布式缓存 7-重启策略 8-Fli ...

  10. group by搭配 order by解决排序问题

    问题 Ftravel_id Facct_no Froute_code Fmodify_time 41010020180725102219102000010452 1359c027b0a15266418 ...