Dinic算法----最大流常用算法之一
——没有什么是一个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算法----最大流常用算法之一的更多相关文章
- POJ1273 网络流-->最大流-->模板级别-->最大流常用算法总结
一般预流推进算法: 算法思想: 对容量网络G 的一个预流f,如果存在活跃顶点,则说明该预流不是可行流. 预流推进算法就是要选择活跃顶点,并通过它把一定的流量推进到它的邻接顶点,尽可能将正的赢余减少为0 ...
- 算法模板——Dinic网络最大流 2
实现功能:同Dinic网络最大流 1 这个新的想法源于Dinic费用流算法... 在费用流算法里面,每次处理一条最短路,是通过spfa的过程中就记录下来,然后顺藤摸瓜处理一路 于是在这个里面我的最大流 ...
- ACM常用算法及练习(2)
ACM常用算法及练习 知识类型 重要度 容易度 应掌握度 典型题 其他 数据结构(5) 链表 ★★☆ ★★★ ★★☆ 栈 stack ★★★ ★★★ ★★★ HLoj120 ...
- ACM常用算法及练习(1)
ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短 ...
- ACM常用算法
数据结构 栈,队列,链表 哈希表,哈希数组 堆,优先队列 双端队列 可并堆 左偏堆 二叉查找树 Treap 伸展树 并查集 集合计数问题 二分图的识别 平衡二叉树 二叉排序树 线段树 一维线段树 二维 ...
- 总结Objective-c常用算法
今天是星期天,想睡到10点起床,结果认为自己太奢侈了,不能这么做,于是把闹钟设置成了6:30:结果终于9:36醒了,起床,无缘无故迟了,好吧,就算太累了吧,周天就原谅自己一回.终于到了中午 ...
- 【小白学游戏常用算法】二、A*启发式搜索算法
在上一篇博客中,我们一起学习了随机迷宫算法,在本篇博客中,我们将一起了解一下寻路算法中常用的A*算法. 通常情况下,迷宫寻路算法可以使用深度优先或者广度优先算法,但是由于效率的原因,不会直接使用这些算 ...
- Atitit 编程语言常用算法attilax总结
Atitit 编程语言常用算法attilax总结 1. 编译算法分类and 数据操作算法.1 1.1. Tab driver stat 状态转换表格算法1 1.2. Nest case 词法分析 ...
- js算法之最常用的排序
引入 大学学习计算机语言的那几年,从c语言,到c++,再到数据结构JAVA..让我印象最深刻的还是最开始老师讲冒泡算法的时候,直到现在大四快毕业了我才渐渐通窍了.刚学前端的时候以为前端就是做出好看很炫 ...
随机推荐
- Java常见错误及解决方案
1.类定义未找到:java.lang.NoClassDefFoundError java类文件没有上传:上传了,服务器没找到,建议将JSP页面重新更新或重启服务器. 2.
- 代码 | 自适应大邻域搜索系列之(3) - Destroy和Repair方法代码实现解析
前言 上一篇文章中我们具体解剖了ALNS类的具体代码实现过程,不过也留下了很多大坑.接下来的文章基本都是"填坑"了,把各个模块一一展现解析给大家.不过碍于文章篇幅等原因呢,也不会每 ...
- 简单创建一个完整的struts2框架小程序
要完成一个struts2框架的搭建, 1.首先应该从官网上下载最新的jar包,网络连接:http://struts.apache.org/download.cgi#struts2514.1,选择下载F ...
- string、char *的转换
string转char* 主要有三种方法可以将str转换为char*类型,分别是:data(); c_str(); copy(); data()方法 string str = "hello& ...
- Zynq-7000 FreeRTOS(二)中断:串口Uart中断
总结Zynq-7000器件的PS上的串口中断,为FreeRTOS中断实验做准备.
- [DPF] DPF 常见的问题
问题一: SQL6031N Error in the db2nodes.cfg file at line number "5". Reason code "12&qu ...
- 拖进Xshell终端窗口文件上传
XShell已经内置rz 直接从Windows拖文件进去终端 http://www.jb51.net/LINUXjishu/163820.html 借助securtCRT,使用linux命令sz可以很 ...
- php array_flip() 删除数组重复元素
在PHP中,用于删除数组中重复元素有一个可用的函数,那就是 array_unique(), 但是它并不是一个最高效的方法,使用array_flip() 函数将比array_uniqure()在速度上高 ...
- LINUX 查找替换命令 总结
find /var/ -name "*.php" > /home/tmp 在/var/目录下查找 所有以.php后缀结尾的文件 结果很多,就 > 输出结果到/home ...
- 【分步详解】两个有序数组中的中位数和Top K问题
(这也是一道leetcode的经典题目:<LeetCode>解题笔记:004. Median of Two Sorted Arrays[H] 问题介绍 这是个超级超级经典的分治算法!!这个 ...