——没有什么是一个BFS或一个DFS解决不了的;如果有,那就两个一起。

最大流的$EK$算法虽然简单,但时间复杂度是$O(nm^2)$,在竞赛中不太常用。

竞赛中常用的$Dinic$算法和$SAP$,其实也不太难。

那么,$Dinic$算法到底是什么呢?


多路增广

$Dinic$算法最核心的内容就是多路增广

沿着$EK$算法的过程:

我们有一个图,如图一。

按照套路,我们先$BFS$,找$S-T$最短路。所有的距离标号都画在了图二上($EK$算法可能用不到,但$Dinic$用得到)。

假设我们选的是$S-3-T$这条路,增广。。。(如图三,绿色)

然后我们再来一遍$BFS$。。。 等等!

细心的你可能也发现了,$S-1-T$也是一条$S-T$最短路。

那就增广吧!(如图四)

您可以检查一下,这时候没有长度为$2$的最短路了。

但EK算法不会这样。它会再笨拙地$BFS$一遍,这就浪费了不少时间。

所以说,多路增广是很重要的。

我们换一种思路,如果网络流在一个$DAG$上,还不用考虑回退边,你会怎么做?

这很简单,$dfs$就能解决。

至于回退边。。。再来一次$BFS-DFS$就好了啊。

还有一个优化:当前弧优化:

对于每个点,我可能在一次$BFS$之后$DFS$多次。那么它出发的边所到的点里, 有些点出发已经满流。

这样, 我就可以每个点记录一个当前弧, 表示这次$DFS$它最后$DFS$到哪条弧,下次$DFS$它的时候就从这条弧开始。

这样,我就可以保证每条边在一次$DFS$中满流后不会再遍历。

这样的复杂度。。。理论上最坏是$O(n^2m)$,但这上界很松。

附代码!

 int n;

 struct Dinic{
struct Edge{
int from, to;
LL cap, flow;
Edge(int f = -, int t = -, LL c = )
:from(f), to(t), cap(c), flow()
{}
}edges[MAXM];
int next[MAXM], cnt;
int pre[MAXN], dis[MAXN];
int cur[MAXN]; //当前弧
Dinic()
{
memset(pre, -, sizeof(pre));
cnt = ;
}
void addedge(int f, int t, LL c)
{
edges[cnt] = Edge(f, t, c);
next[cnt] = pre[f];
pre[f] = cnt++;
edges[cnt] = Edge(t, f, );
next[cnt] = pre[t];
pre[t] = cnt++;
}
queue<int> Q;
bool BFS(int s, int t)
{
while(!Q.empty()) Q.pop();
memset(dis, -, sizeof(dis));
dis[s] = ;
Q.push(s);
while(!Q.empty())
{
int u = Q.front(); Q.pop();
for(int i = pre[u]; i >= ; i = next[i]) if(edges[i].cap > edges[i].flow)
{
int v = edges[i].to;
if(dis[v] >= ) continue;
dis[v] = dis[u] + ;
if(v == t) return true;
Q.push(v);
}
}
return false;
}
LL DFS(int now, int t, LL maxflow) //当前在now,汇点t
{ //最大可以提供maxflow的流量
if(now == t) return maxflow;
int ret = ;
for(int i = cur[now] != - ? cur[now] : pre[now]; i >= ; i = next[i]) if(edges[i].cap > edges[i].flow)
{
int v = edges[i].to;
if(dis[v] != dis[now] + ) continue;
int l = DFS(v, t, min(edges[i].cap - edges[i].flow, maxflow - ret));
ret += l;
edges[i].flow += l;
edges[i^].flow -= l;
cur[now] = i;
if(ret == maxflow) return ret;
}
cur[now] = -;
return ret;
}
LL solve(int s, int t)
{
int res = ;
while(BFS(s,t))
{
memset(cur, -, n * sizeof(int));
res += DFS(s, t, inf);
}
return res;
}
};

Dinic

代码可能有错,烦请指出。谢谢。

另外,如果有人知道些好用的画图软件麻烦推荐一下。用windows自带画图太累了。

Dinic算法----最大流常用算法之一的更多相关文章

  1. POJ1273 网络流-->最大流-->模板级别-->最大流常用算法总结

    一般预流推进算法: 算法思想: 对容量网络G 的一个预流f,如果存在活跃顶点,则说明该预流不是可行流. 预流推进算法就是要选择活跃顶点,并通过它把一定的流量推进到它的邻接顶点,尽可能将正的赢余减少为0 ...

  2. 算法模板——Dinic网络最大流 2

    实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流 ...

  3. ACM常用算法及练习(2)

    ACM常用算法及练习 知识类型 重要度 容易度 应掌握度 典型题 其他           数据结构(5) 链表 ★★☆ ★★★ ★★☆     栈 stack ★★★ ★★★ ★★★ HLoj120 ...

  4. ACM常用算法及练习(1)

    ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短 ...

  5. ACM常用算法

    数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...

  6. 总结Objective-c常用算法

          今天是星期天,想睡到10点起床,结果认为自己太奢侈了,不能这么做,于是把闹钟设置成了6:30:结果终于9:36醒了,起床,无缘无故迟了,好吧,就算太累了吧,周天就原谅自己一回.终于到了中午 ...

  7. 【小白学游戏常用算法】二、A*启发式搜索算法

    在上一篇博客中,我们一起学习了随机迷宫算法,在本篇博客中,我们将一起了解一下寻路算法中常用的A*算法. 通常情况下,迷宫寻路算法可以使用深度优先或者广度优先算法,但是由于效率的原因,不会直接使用这些算 ...

  8. Atitit 编程语言常用算法attilax总结

    Atitit 编程语言常用算法attilax总结 1. 编译算法分类and   数据操作算法.1 1.1. Tab driver stat  状态转换表格算法1 1.2. Nest case 词法分析 ...

  9. js算法之最常用的排序

    引入 大学学习计算机语言的那几年,从c语言,到c++,再到数据结构JAVA..让我印象最深刻的还是最开始老师讲冒泡算法的时候,直到现在大四快毕业了我才渐渐通窍了.刚学前端的时候以为前端就是做出好看很炫 ...

随机推荐

  1. 2016级算法期末模拟练习赛-E.AlvinZH的青春记忆III

    1083 AlvinZH的青春记忆III 思路 难题,二分图. 说这是一个考察二分图的题目,你可以会说"不可能",这哪里像一个二分图了!这真的是一个二分图,考察的是最小顶点覆盖. ...

  2. vue-cli3预设preset记录

    这两天公司搭建新项目的时候发现vue-cli3有一个神奇的的东西:preset(预设).preset其实是你在create新vue项目的时候,生成的插件配置项预设,也就是你在项目中需要用到的插件安装成 ...

  3. GeneXus学习笔记——创建一个知识库 哈哈哈哈!

    终于想到写什么东西了(绝对不是因为懒 好吧 信我)  那么进入正题 我们写项目的时候 遇到一些问题啥的 总会听到大佬说:“这有什么难的 说到底不就是简单的增删改查么"  然后我们就会露出 Σ ...

  4. 让 Linux grep 的输出不换行

    在Redhat中亲测. 本来ps -ef的输出是不会换行的,但是 ps -ef | grep java 就换行了. 如果想让grep完的结果不要换行,找到两种方法. 1. 在后面拼接 less -S: ...

  5. hibernate多对一单向关联注解方式

    多对一单向关联,在多的一方加上一的一方作为外键.在程序里表现为:在多的一方加上一的引用. 小组类Group,用户User: Group: package com.oracle.hibernate; i ...

  6. 【CSS3】background-origin和background-clip的区别

    background-clip 与 background-origin是css3中引入的两个跟元素背景相关的属性,它们有相同的可选值,即border.padding.content三种,而且这两个属性 ...

  7. css中字体单位px,pt,em,百分比之间的区别和用法

    px 即像素,一般国内网站使用较多,默认大小是16px; pt 印刷行业常用单位 em  相对单位,相对父元素属性的单位 ,一般用于移动端布局 rem  结合相对定位和绝对定位的优势,相对根元素htm ...

  8. 个人常用的vba代码

    只做备注 Sub general_sql_macro() Sql = "" column_name = "user_count" Sql = "ins ...

  9. orcale 之游标的属性

    无论是显式游标还是隐式游标都会有四个属性分别是:%ISOPEN.%FOUND.%NOTFOUND.%ROWCOUNT 下面我们分别对着几种属性进行分析. %FOUND 该属性表示当前游标是否指向有效的 ...

  10. Redis之数据类型Sting字符串

    Redis String(字符串) string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value. string类型是二进制安全的.意思是redi ...