引入

最大流算法分为两类,一种是增广路算法,一种是预留推进算法。增广路算法包括时间复杂度\(O(nm^2)\)的EK算法,上界为\(O(n^2m)\)的Dinic算法,以及一些其他的算法。EK算法直接进行增广,而Dinic则是通过沿着最短路增广优化了复杂度,它的做法是每次进行bfs求出层次图,再dfs沿着层次图进行多路增广。然而,Dinic中每次进行bfs求层次图似乎有点浪费,因为层次图的改动并不是非常大。在这种思路下,我们考虑直接在每次dfs增广的时候修改层次图来优化求最短路的过程。

算法

ISAP (Improved Shortest Augment Path) 算法其实是通过dfs中不断修改距离标号\(d\)的方式省去了每次的bfs,所以称为improved。

Dinic算法中,我们需要每次搜索出层次图,而在ISAP中,我们只需要每次dfs的过程中修改距离标号。具体来说,我们用\(d[x]\)表示残余网络上\(x\)到汇点\(t\)的最短距离,我们每次沿着\(d[x]=d[v]+1\)的路增广。如果点\(x\)的出边的点没有发现满足这个条件的那么就说明当前的最短路已经过时了,我们需要修改距离标号。修改距离标号,就是让\(x\)可以至少有一个点可以增广,所以取所有\(d[v]\)中最小的那个加一即可。这样增广下去,当\(d[s]\),即\(s\)到\(t\)的距离大于等于\(n\)的时候,就说明至少有一个点经过了两次,即不存在增广路了,这个时候算法退出。

复杂度

ISAP的复杂度上界其实就是Dinic复杂度去掉bfs的部分。接下来我们证明Dinic的复杂度,再说明ISAP的复杂度上界。

Dinic算法每次求出层次图,然后dfs多路增广。可以发现,当dfs退出的时候,可以增广的所有路径都已经增广完了。考虑每一次\(t\)的层次标号,可以发现,如果一次dfs完,下一次bfs得到\(t\)的层次标号与上一次一样,那么就是说,上一次还有没有增广完的路径,这显然是不可能的。那么\(t\)的层次标号是否可能减少呢?如果可以的话,那么上一次也可以找到更短的路径,因为残余网络的增广会把边变成反向。这样,每次bfs的时候得到的\(t\)层次编号是严格递增的,也就是说,\(n\)次阶段以内一定可以结束算法。bfs的复杂度为\(O(m)\),dfs的复杂度看似是\(O(m)\)的,其实不然。考虑一个满足\((u,v,w)\),其中\(w\)为\(v\)可以到达的点的数量的网络流原图,那么一次dfs可以达到\(nm\)。这样看来,整个过程分成了\(n\)个阶段,每一阶段为\(O(nm)\),所以总共是\(O(n^2m)\)。

ISAP的复杂度上界与这个是相同的。

优化

接下来我们将看到ISAP是如何被极大地优化的。

  • 如果一开始把距离标号都设为0,那么dfs最多需要\(O(n^2)\)来把距离标号初始化,而我们可以最开始逆向bfs一次,\(O(n+m)\)初始化所有距离标号。
  • 如果距离标号出现了断层,那么显然不存在新的增广路。我们用一个gap数组记录每种层次标号有多少个,如果当前修改了最后一个某种层次标号,那么就出现了前后断层,结束算法。
  • 增广过程中,如果一个点的标号没有修改过,那么它已经遍历过的边不需要再遍历一次,所以我们存下每次遍历到哪条边,下一次从这条边开始遍历(因为有可能到这里之后流量用完了,但是还没有增广完)。
  • 最短路的修改具有连续性,即我们不需要每次求后继的标号最小值,而是直接给标号加一。
  • 同Dinic中,如果流量用完了直接退出。

ISAP非常好地结合标号的思想优化了SAP算法,编程复杂度极低(我的递归版主过程只有30行),可以作为网络流算法的首选。

UPDATE:谁能告诉我ISAP在什么数据下会被卡掉!!

代码

poj1273网络流模板题。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
int read() {
int x=0,f=1;
char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const int maxn=205;
const int maxm=205;
const int inf=2e9+7;
struct edge {
int v,w,nxt;
} e[maxm<<1];
int h[maxn],tot,n,m,gap[maxn],last[maxn],d[maxn],que[maxn],ql,qr;
vector<int> inv[maxn];
void add(int u,int v,int w) {
e[++tot]=(edge){v,w,h[u]};
h[u]=tot;
e[++tot]=(edge){u,0,h[v]};
h[v]=tot;
}
void init(int s,int t) {
memset(gap,0,sizeof gap),memset(d,0,sizeof d),++gap[d[t]=1];
for (int i=1;i<=n;++i) last[i]=h[i];
que[ql=qr=1]=t;
while (ql<=qr) {
int x=que[ql++];
for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (!d[v]) ++gap[d[v]=d[x]+1],que[++qr]=v;
}
}
int aug(int x,int s,int t,int mi) {
if (x==t) return mi;
int flow=0;
for (int &i=last[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if (d[x]==d[v]+1) {
int tmp=aug(v,s,t,min(mi,e[i].w));
flow+=tmp,mi-=tmp,e[i].w-=tmp,e[i^1].w+=tmp;
if (!mi) return flow;
}
if (!(--gap[d[x]])) d[s]=n+1;
++gap[++d[x]],last[x]=h[x];
return flow;
}
int maxflow(int s,int t) {
init(s,t);
int ret=aug(s,s,t,inf);
while (d[s]<=n) ret+=aug(s,s,t,inf);
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
while (~scanf("%d%d",&m,&n)) {
tot=1,memset(h,0,sizeof h);
for (int i=1;i<=n;++i) inv[i].clear();
for (int i=1;i<=m;++i) {
int u=read(),v=read(),w=read();
add(u,v,w);
if (w) inv[v].push_back(u);
}
int ans=maxflow(1,n);
printf("%d\n",ans);
}
return 0;
}

最大流算法-ISAP的更多相关文章

  1. 最大流算法 ISAP 模板 和 Dinic模板

    ISAP // UVa11248 Frequency Hopping:使用ISAP算法,加优化 // Rujia Liu struct Edge { int from, to, cap, flow; ...

  2. Ford-Fulkerson 最大流算法

    流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0.如果 (u, v) ∉ E 则可以规定 c(u, ...

  3. 算法9-5:最大流算法的Java代码

    残留网络 在介绍最大流算法之前先介绍一下什么是残留网络.残余网络的概念有点类似于集合中的补集概念. 下图是残余网络的样例. 上面的网络是原始网络.以下的网络是计算出的残留网络.残留网络的作用就是用来描 ...

  4. 海量数据挖掘MMDS week3:流算法Stream Algorithms

    http://blog.csdn.net/pipisorry/article/details/49183379 海量数据挖掘Mining Massive Datasets(MMDs) -Jure Le ...

  5. 基于.net的分布式系统限流组件(限流算法:令牌算法和漏斗算法)

    转载链接:https://www.cnblogs.com/vveiliang/p/9049393.html 1.令牌桶算法 令牌桶算法是比较常见的限流算法之一,大概描述如下: 1).所有的请求在处理之 ...

  6. 常用限流算法与Guava RateLimiter源码解析

    在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...

  7. Cable TV Network 顶点连通度 (最大流算法)

    Cable TV Network 题目抽象:给出含有n个点顶点的无向图,给出m条边.求定点联通度   K 算法:将每个顶点v拆成 v'   v''  ,v'-->v''的容量为1.       ...

  8. 最大流算法之ISAP

    序: 在之前的博文中,我解释了关于最大流的EK与Dinic算法,以及它们的STL/非STL的实现(其实没什么区别).本次讲解的是ISAP算法.'I',指 inproved,也就是说ISAP其实是SAP ...

  9. 最大流算法-最高标号预流推进(HLPP)

    昨天我们学习了ISAP算法,它属于增广路算法的大类.今天学习的算法是预流推进算法中很高效的一类--最高标号预流推进(HLPP). 预流推进 预流推进是一种很直观的网络流算法.如果给到一个网络流让你手算 ...

随机推荐

  1. 虚拟机安装&Linux初探

    学习基于VirtualBox虚拟机安装Ubuntu图文教程在自己笔记本上安装Linux操作系统 安装虚拟机的过程还算顺利.除了在安装增强设备功能时需要将之前的硬盘弹出之外,没有遇到其他的问题. 通过实 ...

  2. 用sudo 运行命令的时候,环境变量用的是super用户的环境变量

    比如今天在~/.bashrc设置了JAVA_HOME, 而sudo运行命令的时候却显示没有设置可用的JAVA_HOME

  3. 【洛谷P4178】Tree

    题面 题解 感觉和\(CDQ\)分治一样套路啊 首先,构建出点分树 对于每一层分治重心,求出它到子树中任意点的距离 然后\(two-pointers\)计算满足小于等于\(K\)的点对数目,加入答案 ...

  4. 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition

    Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...

  5. linux 同步 rsync的使用——远程服务器同步配置

    一.背景介绍 由于需要和其他系统进行对接.文件的逻辑地址通过接口传递,而文件的实体需要通过服务器间的同步进行传输.在同事的建议下选择了rsync. 二.RSYNC介绍 RSYNC 有多种方式进行同步, ...

  6. asp.net 问题:Web 服务器上的请求筛选模块被配置为 拒绝包含的查询字符串过长的请求

    发现问题: post请求,在发送一个图片base64编码的字符串时,服务端报这个错误. 报错信息中给出了解决办法: 最可能的原因: Web 服务器上的请求筛选被配置为拒绝该请求,因为查询字符串过长. ...

  7. Swoole实现h5版聊天室笔记

    声明:该聊天室目前只有一对多,一对一的聊天功能,另外,因为没有使用到mysql,所以还存在比较多的缺陷地方,但知道原理就差不多了,这里主要分享下swoole简易的聊天室制作思路. 开发环境:cento ...

  8. Python接口测试实战3(下)- unittest测试框架

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  9. Eclipse 无法编译 或 提示“错误: 找不到或无法加载主类”

    project显示一个红色叹号,通常是.jar文件缺失,在下面找到配置 在libraries中添加add External JARs添加.jar文件

  10. 虚拟货币——比特币行情价格分析

    最近挖以太币的朋友们在关注以太坊行情时,一定会发现以太币的价格对比之前上涨了不少.肯定有部分朋友想了解这次上涨的原因,我们特地为此查询了一番.因为比特币相当于虚拟货币中的黄金,它的价格波动会波及到其他 ...