网络流Dinic(本篇介绍最大流)
前言
看到网上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(本篇介绍最大流)的更多相关文章
- 再写一篇tps限流
再写一篇tps限流 各种限流算法的称呼 网上有很多文章介绍限流算法,但是对于这些算法的称呼与描述也是有点难以理解.不管那么多了.我先按我理解的维度梳理一下. 主要维度是:是正向计数还是反向计数.是定点 ...
- 国内首篇介绍JanOS物联网操作系统的文章 - 如何把你的手机主板打造成物联网平台
天地会珠海分舵注:如无意外,您现在正在看的将是国内首篇且是唯一一篇介绍炙手可热的物联网的操作系统JanOS的文章!不信你去百度!希望大家能喜欢.但本文只是引言,更多信息请还是访问JanOS的官网:ht ...
- POJ 1273 Drainage Ditches (网络流Dinic模板)
Description Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover ...
- Java并发包下锁学习第一篇:介绍及学习安排
Java并发包下锁学习第一篇:介绍及学习安排 在Java并发编程中,实现锁的方式有两种,分别是:可以使用同步锁(synchronized关键字的锁),还有lock接口下的锁.从今天起,凯哥将带领大家一 ...
- spring cloud系列教程第一篇-介绍
spring cloud系列教程第一篇-介绍 前言: 现在Java招聘中最常见的是会微服务开发,微服务已经在国内火了几年了,而且也成了趋势了.那么,微服务只是指spring boot吗?当然不是了,微 ...
- 老猿学5G扫盲贴:推荐三篇介绍HTTP2协议相关的文章
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 5G中的服务化接口调用都是基于HTTP2协议的,老 ...
- 网络流小记(EK&dinic&当前弧优化&费用流)
欢 迎 来 到 网 络 瘤 的 世 界 什么是网络流? 现在我们有一座水库,周围有n个村庄,每个村庄都需要水,所以会修水管(每个水管都有一定的容量,流过的水量不能超过容量).最终水一定会流向唯一一个废 ...
- POJ 2987 Firing 最大流 网络流 dinic 模板
https://www.cnblogs.com/137shoebills/p/9100790.html http://poj.org/problem?id=2987 之前写过这道题,码一个dinic的 ...
- POJ 3281(Dining-网络流拆点)[Template:网络流dinic]
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmlrZTBnb29k/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA ...
随机推荐
- 外部访问docker中的MySQL
注:192.168.1.203机器上装有docker,容器在该机器上 mysql> use mysql; mysql> update user set authentication_str ...
- Docker Selenium
SeleniumHQ官方项目:https://github.com/seleniumHQ/docker-selenium 项目目前快速迭代中. Docker 一般叫docker容器,一个可爱的鲸鱼,上 ...
- 越狱解决iphone4s外放无声音
删除iphone中/System/Library/PrivateFrameworks/IAP.framework/Support/目录下的iapd文件 进入/SYSTEM/Library/Launch ...
- C++笔记-并发编程 异步任务(async)
转自 https://www.cnblogs.com/diysoul/p/5937075.html 参考:https://zh.cppreference.com/w/cpp/thread/lock_g ...
- postman的使用大全
转载 https://blog.csdn.net/fxbin123/article/details/80428216
- vs2015第二次装安装不能选择路径问题解决方法
vs2015卸载后注册表还会存在vs2015的信息,下次安装的时候会读注册表里面记录的路径,不能自己选择路径. 解决方法: 1.在vs安装文件的路径打开命令,shift+鼠标右键 2.输入命令:cn_ ...
- Mybatis逆向工程 —— ResultMaps collection already contains value for ***
报错提示: Result Maps collection already contains value for ***. 遭遇场景: maven+ssm 项目中,采用了mybatis的逆向工程生成 p ...
- 安装VM-tools
win10系统 VMware12 Ubuntu64位安装VM-tools时所遇到的提示信息: open-vm-tools are available from the OS vendor and VM ...
- 手动用tomcat启动war包,无法访问web项目
先说一下自己采的小坑,网上大多解答都是复制来复制去,不说重点在哪.我这里简单总结下访问路径问题 一.用idea打成war包,具体步骤如下图: 步骤:在项目配置选Artifacts新建Web Appli ...
- Redhat6.4安装Oracle 11gr2 64位 注意事项
安装步骤略, 安装步骤参考:https://www.cnblogs.com/jhlong/p/5442459.html 注意的是,会出现找不到一些依赖库,我根据光盘已有的库安装了所有64位的依赖库,强 ...