主要还是板子

Edmonds-Karp

从S开始bfs,直到找到一条到达T的路径后将该路径增广,并重复这一过程。

在处理过程中,为了应对“找到的一条路径把其他路径堵塞”的情况,采用了建反向弧的方式来实现“反悔”过程。

这种“反悔”的想法和技巧值得借鉴。

 int maxFlow()
{
int ret = ;
for (;;)
{
memset(f, , sizeof f);
memset(bck, , sizeof bck);
std::queue<int> q;
f[S] = INF, q.push(S);
for (int tmp; q.size(); )
{
tmp = q.front(), q.pop();
for (int i=head[tmp]; i!=-; i=nxt[i])
{
int v = edges[i].v;
if (!f[v]&&edges[i].f < edges[i].c){
f[v] = std::min(f[tmp], edges[i].c-edges[i].f);
bck[v] = i, q.push(v);
}
}
if (f[T]) break;
}
if (!f[T]) break;
for (int i=T; i!=S; i=edges[bck[i]].u)
{
edges[bck[i]].f += f[T];
edges[bck[i]^].f -= f[T];
}
ret += f[T];
}
return ret;
}

Dinic

EK的效率是$O(nm^2)$的,它把很多时间浪费在了重复的搜索上面。

dinic有如下两个重要的定义:

  • 层次$\text{level(x)}$:表示点$x$在层次图中与源点$S$的距离。
  • 层次图:在原来的残量网络当中,只保留所有可被增广的边以及与之相连的点。

bfs建出来的层次图对于接下去的dfs增广具有一种“指导”作用。使用了反向弧技巧,意味着不管用什么方法,只需要找到一条增广路就行。在这种情况下,我们来考虑dfs增广的优劣之处:一方面它一旦找到一条增广路就能快速退出,比bfs的逐级外扩更高效;另一方面纯粹的dfs受搜索顺序的影响很大,因为(可以像卡SPFA以及某些图论算法一样)挂一些诱导节点附带数量巨大的边,就能置dfs于死地。但是这里dfs依靠建出来的层次图,每次只向距离+1的点搜索。这意味着我们避免了对同一个节点的重复搜索,或是偏离T方向浪费时间。

 bool buildLevel()
{
memset(lv, , sizeof lv);
std::queue<int> q;
q.push(S), lv[S] = ;
for (int i=; i<=T; i++) cur[i] = head[i];   //tip1
for (int tmp; q.size(); )
{
tmp = q.front(), q.pop();
for (int i=head[tmp]; i!=-; i=nxt[i])
{
int v = edges[i].v;
if (!lv[v]&&edges[i].f < edges[i].c){
lv[v] = lv[tmp]+, q.push(v);
if (v==T) return true;        //tip2
}
}
}
return false;
}
int fndPath(int x, int lim)        //此处已更新,详情见下
{
if (x==T) return lim;
for (int &i=cur[x]; i!=-; i=nxt[i])       //tip1
{
int v = edges[i].v, val;
if (lv[x]+==lv[v]&&edges[i].f < edges[i].c){
if ((val = fndPath(v, std::min(lim, edges[i].c-edges[i].f)))){
edges[i].f += val, edges[i^].f -= val;
return val;
}else lv[v] = -;             //tip3  
}
}
cur[x] = head[x];
return ;
}
int dinic()
{
int ret = , val;
while (buildLevel())
while ((val = fndPath(S, INF))) ret += val;
return ret;
}

dinic有三个常见优化:

tip1当前弧优化:这个优化是针对边的,有些网络流的边数巨大。这个优化是为了确保在同一层次图的多次增广当中,可以实现“从上一次成功增广停下的地方再次开始”这一个功能。

tip2层次图优化:每次建层次图只需要达到T即可。

tip3堵塞点优化:姑且这么叫吧……在同一层次图下,一个点若未被增广则再也不会被增广了。

个人觉得tip3的效果最明显。tip1是为了少遍历一些边,但是节省的只不过是遍历(因为并不执行操作)的代价;tip2是看脸的优化;tip3应该算是强剪枝。

3.5upd:

今天写最大权闭合子图时候,才发现我学了个假的dinic.

当时是照着menci的 Dinic 学习笔记 学的dinic,然而今天才发现,menci的指针小常数真的是非常人可比拟的……

就拿bzoj1497: [NOI2006]最大获利来说吧:同样的流程结构,我结构体写法用时7.5s;menci的指针版本只需要0.75s(本地不开O2),这比我加满优化(包括改成以下这个写法)都要快得多……

dinic需要多路优化,而非以上dfs提到的每次寻找到一条增广路就退出。

正经的板子:

 bool buildLevel()
{
std::queue<int> q;
memset(lv, , sizeof lv);
lv[S] = , q.push(S);
for (int i=; i<=T; i++) cur[i] = head[i];
for (int tmp; q.size(); )
{
tmp = q.front(), q.pop();
for (int i=head[tmp]; i!=-; i=nxt[i])
{
int v = edges[i].v;
if (!lv[v]&&edges[i].f < edges[i].c){
lv[v] = lv[tmp]+, q.push(v);
if (v==T) return true;
}
}
}
return false;
}
int fndPath(int x, int lim)
{
int sum = ;
if (x==T||!lim) return lim;
for (int i=cur[x]; i!=-&&sum <= lim; i=nxt[i])
{
int v = edges[i].v, val;
if (lv[x]+==lv[v]&&edges[i].f < edges[i].c){
if ((val = fndPath(v, std::min(lim-sum, edges[i].c-edges[i].f)))){
edges[i].f += val, edges[i^].f -= val;
sum += val;
}else lv[v] = -;
}
      if (lim==sum) break;        //小trick的效果是玄学致命的
}
cur[x] = head[x];
return sum;
}
int dinic()
{
int ret = , val;
while (buildLevel())
while ((val = fndPath(S, INF))) ret += val;
return ret;
}

初涉网络流[EK&dinic]的更多相关文章

  1. [知识点]网络流之Dinic算法

    // 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html      ...

  2. [无效]网络流之Dinic算法

    // 此博文为迁移而来,写于2015年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html UPDA ...

  3. 图论算法-最小费用最大流模板【EK;Dinic】

    图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...

  4. 图论算法-网络最大流【EK;Dinic】

    图论算法-网络最大流模板[EK;Dinic] EK模板 每次找出增广后残量网络中的最小残量增加流量 const int inf=1e9; int n,m,s,t; struct node{int v, ...

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

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

  6. 初探网络流:dinic/EK算法学习笔记

    前记 这些是初一暑假的事: "都快初二了,连网络流都不会,你好菜啊!!!" from 某机房大佬 to 蒟蒻我. flag:--NOIP后要学网络流 咕咕咕------------ ...

  7. HDU1532_Drainage Ditches(网络流/EK模板/Dinic模板(邻接矩阵/前向星))

    Drainage Ditches Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  8. hiho一下,第115周,FF,EK,DINIC

    题目1 : 网络流一·Ford-Fulkerson算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho住在P市,P市是一个很大很大的城市,所以也面临着一个 ...

  9. 网络流EK

    #include <iostream> #include <queue> #include <string.h> #define MAX 302 using nam ...

随机推荐

  1. 爬虫基础(1):urllib库

    urllib库 urllib库是python中的一个基本网络请求库.用于模拟浏览器的行为,向指定服务器发送请求,并接收返回的数据. 在python3中所有的网络请求相关函数都集中在urllib.req ...

  2. XML与JSON的区别

    JSON和XML的比较 ◆可读性 JSON和XML的可读性可谓不相上下,一边是简易的语法,一边是规范的标签形式,很难分出胜负. ◆可扩展性 XML天生有很好的扩展性,JSON当然也有,没有什么是XML ...

  3. NET Core学习方式(视频)

    NET Core学习方式(视频) ASP.NET Core都2.0了,它的普及还是不太好.作为一个.NET的老司机,我觉得.NET Core给我带来了很多的乐趣.Linux, Docker, Clou ...

  4. Qt5.7中使用MySQL Driver(需要把libmysql.dll文件拷贝到Qt的bin目录中。或者自己编译的时候,链接静态库)

    Qt5.7中使用MySQL Driver 1.使用环境 Qt5.7的安装安装就已经带了MySQL Driver,只需要在安装的时候选择一下即可.如果没有安装,可以采取自己编译的方式.在Qt的源码包的q ...

  5. Solr创建索引问题

    问题描述: 8月 19, 上午10点27:58.219 WARN com.ngdata.hbaseindexer.supervisor.IndexerSupervisor No indexer pro ...

  6. 牛客网Java刷题知识点之抽象类与接口

    不多说,直接上干货! 接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是Java语言中对抽象概念进行定义的两种机制,正是由于它们的存在才赋予java强大的面向对象的能力. ...

  7. Dell服务器安装系统中遇到的坑

    在本学期开学初期,由于后续实验的需要,老师为我们配置了服务器,该服务器的型号为Dell Power R730. 由于我也是一个小白,在服务器安装系统的过程中,遇到了一些麻烦,在这里记录下来,希望自己能 ...

  8. noip搜索模拟题 骰子

    骰子 dice.cpp/c/pas 1s/128M [题目描述] 桌面上有两个特别的骰子.骰子的每一个面,都写了一个不同的数字.设第一个骰子上下左右前后分别为a1, a2, a3, a4, a5, a ...

  9. python基础---有关nparray----切片和索引(一)

    Numpy最重要的一个特点就是其N维数组对象,即ndarray,该对象是一种快速而灵活的大数据集容器,实际开发中,我们可以利用这种数组对整块数据执行一些数学运算. 有关ndarray,我们就从最简单的 ...

  10. windows服务器安装安全狗时服务名如何填写

    安全狗安装时“服务名”这一栏指的是apache进程的服务名称,即进入“任务管理-服务”里显示的名称. phpstudy等软件搭建的环境需要设置运行模式为“系统服务”后才能看到服务名.