主要还是板子

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. java课后思考题(六)

    1.使用Files. walkFileTree()找出指定文件夹下所有扩展名为.txt和.java的文件. import java.io.IOException;import java.nio.fil ...

  2. (转)nginx应用总结(2)--突破高并发的性能优化

    原文:http://www.cnblogs.com/kevingrace/p/6094007.html 在日常的运维工作中,经常会用到nginx服务,也时常会碰到nginx因高并发导致的性能瓶颈问题. ...

  3. windows无法启动redis服务,错误码1067

    https://blog.csdn.net/kissdead0xzy/article/details/84332870

  4. kie-api 组件介绍

    KieServices:kie整体的入口,可以用来创建Container,resource,fileSystem等 KieContainer: KieContainer就是一个KieBase的容器,可 ...

  5. nodejs模块学习: webpack

    nodejs模块学习: webpack nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固,需要开发者创造大量的轮子来解决现实 ...

  6. IDEA2017 配置Maven

    配置本地仓库位置 配置一下Maven的本地仓库路径,首先找到解压Maven的目录,找到conf -> settings.xml这个配置文件打开. 打开settings.xml 配置文件,选一个本 ...

  7. jetty启动(server-connector-handle-start-join)

    import java.io.File; import java.io.IOException; import java.util.Map; import javax.servlet.ServletE ...

  8. Java transient关键字使用

    1. transient的作用及其使用方法 我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的 ...

  9. Image(支持 XML 序列化),注意C#中原生的Image类是无法进行Xml序列化的

    /// <summary> /// Image(支持 XML 序列化) /// </summary> [XmlRoot("XmlImage")] publi ...

  10. 命令方式重新签名apk

    1.(每个指令之间要有一个空格) 注:拿到一个apk后,首先删除META-INF. 1.如果你的电脑装的是jdk1.6,就用下面的命令: 打开命令符,首先直接输入: Jarsigner -keysto ...