前言

看到网上Dinic和ISAP的比较,多数人认为ISAP更快,不容易爆栈。当然,也有少数人认为,在多数情况下,Dinic比较稳定。我认为Dinic的思路比ISAP更简明,所以选择了Dinic算法

UPD20190626:突然发现这篇博客阅读量1000多了,把我吓得不轻,感谢各位网友的支持。

介绍

Dinic算法本身,自然是解决最大流(普通最大流,最大流最小割)的算法。通过处理,也可以解决二分图的最大匹配(下文介绍),最大权闭合图。

算法介绍:介绍Dinic之前,我们先介绍一下最大流。在最大流的题目中,图被称为"网络",每条边的边权被称作"流量",有一个起点(源点)和一个终点(汇点)。我们要求的最大流,可以这样形象地理解:源点有一个水库,里面有无限吨水(QWQ),汇点也有一个水  库,希望得到最多的水。我们假设每个河道一天只能输水n吨(及网络流中的流量),求解汇点最多能的到几吨水。再给一个正式的定义:最大流是指网络中满足弧流量限制条件和平衡条件且具有最大流量的可行流

下面我们正式介绍Dinic:

首先引出网络流算法中的链,给个正式定义:链是网络中的一个顶点序列,这个序列中前后两个顶点有弧相连(其实我认为这个定义无关紧要,所以重点看下面弧的定义)。

弧 :弧分为两种,第一种是前向弧是指方向和链一致的弧(简单的说就是输入的边)---前向弧,第二种弧是指方向和链不一致的弧(简单的说就是输入的边反一反)---后向弧。

好了接下来要引出一个网络流算法的重要概念

增广路

给个正式的定义:

1、增广路是一条链

2、链上的前向弧都是非饱和弧

链上的后向弧都是非零弧

3、链是由源点到汇点的

总结一下:额...这听起来好像啥都没说(滑稽)

谈谈我的理解:

增广路是一个边集,是一条从源点到汇点的路径

增广路有一个权值表示该增广路的最大流量,而最大流量的大小是边集中流量最小的边的流量。

剩余网络

由反向弧组成的网络,关于反向弧的权的问题,后文会介绍。

说了一大堆,下面正式介绍Dinic算法

Dinic算法的大致步骤

1、建立网络(包括正向弧和反向弧(初始边权为0)),将总流量置为0

2、构造层次网络(怎么又有新概念 T_T)

简单的说,就是求出每个点u的层次,u的层次是从源点到该点的最短路径(注意:这个最短路是指弧的权都为1的情况下的最短路),若与源点不连通,层次置为-1

一遍BFS轻松解决

3、判断汇点的层次是否为-1

是:再见,算法结束,输出当前的总流量

否:下一步

4、用一次DFS完成所有增广,增广是什么呢?

增广(我的理解):通过DFS找上述的增广路,找到了之后,将每条边的权都减去该增广路中拥有最小流量的边的流量,将每条边的反向边的权增加这个值,同时将总流量加上这个值

DFS直到找不到一条可行的从原点到汇点的路

5、goto 步骤2

细节处理,如何快速找到一条边的反向边:边的编号从0开始,反向边加在正向边之后,反向边即为该点的编号异或1

复杂度:理论上来说,最慢应该是O((n^2)*m),n表点数,m表边数,实际上呢,应该快得不少

代码实例:(参见洛谷P3376)

传送门[>洛谷<]   重要提示:您的等级必须达到蓝色以上,否则后果自负

当前弧优化

在DFS的时候记录当前已经计算到第几条边了,避免重复计算。

那么具体原理是什么呢?

每当我们发现一条新的增广路时,由于算法"贪心"的性质,该增广路上的可用流量其实已经被支配完全(即使放入另一条增广路也毫无意义)。

那么当我们每次到达一个节点时,必定有许多边已经被完全支配,又由于我们深度优先搜索的性质,故可以记录上一次搜索到哪一条边,下一次直接从该边开始DFS。

在下一次构建层次网络时注意将head数组还原

代码

* 使用当前弧优化

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm> using namespace std; const int MAX = (1ll << 31) - 1; int read(){
int x = 0; int zf = 1; char ch = ' ';
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
} struct Edge{
int to;
int dis;
int next;
} edges[210000]; int cur[10010], head[10010], edge_num = -1;
int n, m, s, t; void addEdge2(int from, int to, int dis){
edges[++edge_num].to = to;
edges[edge_num].dis = dis;
edges[edge_num].next = head[from];
head[from] = edge_num;
} void addEdge(int from, int to, int dis){
addEdge2(from, to, dis), addEdge2(to, from, 0);
} int d[10010]; int DFS(int u, int flow){
if (u == t) return flow;
int _flow = 0, __flow;
for (int& c_e = cur[u]; c_e != -1; c_e = edges[c_e].next){
int v = edges[c_e].to;
if (d[v] == d[u] + 1 && edges[c_e].dis > 0){
__flow = DFS(v, min(flow, edges[c_e].dis));
flow -= __flow;
edges[c_e].dis -= __flow;
_flow += __flow;
edges[c_e^1].dis += __flow;
if (!flow)
break;
}
}
if (!_flow) d[u] = -1;
return _flow;
} bool BFS(){
memset(d, -1, sizeof(d));
queue<int> que; que.push(s);
d[s] = 0; int u, _new;
while (!que.empty()){
u = que.front(), que.pop();
for (int c_e = head[u]; c_e != -1; c_e = edges[c_e].next){
_new = edges[c_e].to;
if (d[_new] == -1 && edges[c_e].dis > 0){
d[_new] = d[u] + 1;
que.push(_new);
}
}
}
return (d[t] != -1);
} void dinic(){
int max_flow = 0;
while (BFS()){
for (int i = 1; i <= n; ++i) cur[i] = head[i];
max_flow += DFS(s, MAX);
}
printf("%d", max_flow);
} int main(){
n = read(), m = read(), s = read(), t = read();
memset(head, -1, sizeof(head));
for (int i = 0; i < m; i++){
int u = read(), v = read(), w = read();
addEdge(u, v, w);
}
dinic();
return 0;
}

算法主要应用场景

1、裸的最大流

2、二分图的最大匹配:建一个点S,连到二分图的集合A中;建一个点T,连到二分图的集合B中。再将所有的集合A中的点与集合B中的点相连。全部边权设为1,跑一遍最大流,结果即为二分图的最大匹配

3、最小割(定义自行百度):在单源单汇流量图中,最大流等于最小割

4、求最大权闭合图(定义自行百度):最大权值=正点权之和-最小割

主要问题:

  为什么要建立反向边?

  Answer:总结多篇博客,认为建立反向边旨在增加重新调整流的机会,即保障解是最优的(还是没有理解?可以自行百度:D)。

版权申明:未经博主允许禁止转载

网络流Dinic(本篇介绍最大流)的更多相关文章

  1. 再写一篇tps限流

    再写一篇tps限流 各种限流算法的称呼 网上有很多文章介绍限流算法,但是对于这些算法的称呼与描述也是有点难以理解.不管那么多了.我先按我理解的维度梳理一下. 主要维度是:是正向计数还是反向计数.是定点 ...

  2. 国内首篇介绍JanOS物联网操作系统的文章 - 如何把你的手机主板打造成物联网平台

    天地会珠海分舵注:如无意外,您现在正在看的将是国内首篇且是唯一一篇介绍炙手可热的物联网的操作系统JanOS的文章!不信你去百度!希望大家能喜欢.但本文只是引言,更多信息请还是访问JanOS的官网:ht ...

  3. POJ 1273 Drainage Ditches (网络流Dinic模板)

    Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover ...

  4. Java并发包下锁学习第一篇:介绍及学习安排

    Java并发包下锁学习第一篇:介绍及学习安排 在Java并发编程中,实现锁的方式有两种,分别是:可以使用同步锁(synchronized关键字的锁),还有lock接口下的锁.从今天起,凯哥将带领大家一 ...

  5. spring cloud系列教程第一篇-介绍

    spring cloud系列教程第一篇-介绍 前言: 现在Java招聘中最常见的是会微服务开发,微服务已经在国内火了几年了,而且也成了趋势了.那么,微服务只是指spring boot吗?当然不是了,微 ...

  6. 老猿学5G扫盲贴:推荐三篇介绍HTTP2协议相关的文章

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 5G中的服务化接口调用都是基于HTTP2协议的,老 ...

  7. 网络流小记(EK&dinic&当前弧优化&费用流)

    欢 迎 来 到 网 络 瘤 的 世 界 什么是网络流? 现在我们有一座水库,周围有n个村庄,每个村庄都需要水,所以会修水管(每个水管都有一定的容量,流过的水量不能超过容量).最终水一定会流向唯一一个废 ...

  8. POJ 2987 Firing 最大流 网络流 dinic 模板

    https://www.cnblogs.com/137shoebills/p/9100790.html http://poj.org/problem?id=2987 之前写过这道题,码一个dinic的 ...

  9. POJ 3281(Dining-网络流拆点)[Template:网络流dinic]

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmlrZTBnb29k/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...

随机推荐

  1. realm swift调研--草稿

    realm swift调研: After you have added the object to the Realm you can continue using it, and all chang ...

  2. 利用XShell上传、下载文件(使用sz与rz命令)

    XSHELL工具上传文件到Linux以及下载文件到本地(Windows)   Xshell很好用,然后有时候想在windows和linux上传或下载某个文件,其实有个很简单的方法就是rz,sz.首先你 ...

  3. CentOS 7 软件安装简记

    Install SW Record ================= $ sudo yum install vim-X11.x86_64 $ sudo yum install clang.x86_6 ...

  4. ARC089E GraphXY 构造

    传送门 在Luogu上评了"NOI"之后评级变成了"普及+/提高"--我觉得我可能要退群了 考虑构造一个这样的图: 其中上半部分是从\(S\)开始的一条长\(1 ...

  5. FineUIPro v5.1.0 发布了!

    FineUIPro v5.1.0 已发布,这已经是自 2014 年以来的第 31 个版本,4 年来精雕细琢,只为你来! 上个大版本新增了响应式布局,而这个版本主要是BUG修正,此外还增加了树控件的级联 ...

  6. Linux配置外网访问mysql

    stream{    upstream abc{        server 192.168.8.249:3306;    }    server{        listen 9211 ; prox ...

  7. redis--主从同步,故障切换,集群搭建

    一 . redis主从同步 准备三个配置文件,实现一主两从的redis数据库结构(这三个配置文件仅仅端口不一样) # redis-6379.conf 文件, 写入下面数据: port 6379 dae ...

  8. codeforces733C

    Epidemic in Monstropolis CodeForces - 733C 有n条鱼排成一列,第i条鱼大小为ai,根据自然界的生存法则,相邻的两只鱼中,较大的鱼可以吃掉较小的鱼,如果两条鱼大 ...

  9. BugKu 这是一张单纯的图片

    http://123.206.87.240:8002/misc/1.jpg FLAG在哪里?? 吐槽一下这图片一点也不单纯 用010 打开后发现最后附着一段意义不明的字符,file命令也识别不出来 题 ...

  10. VueRouter和Vue生命周期(钩子函数)

    一.vue-router路由 1.介绍 vue-router是Vue的路由系统,用于定位资源的,在页面不刷新的情况下切换页面内容.类似于a标签,实际上在页面上展示出来的也是a标签,是锚点.router ...