引入

最大流算法分为两类,一种是增广路算法,一种是预留推进算法。增广路算法包括时间复杂度\(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. MySql访客连接设置

    步骤: 1 . 打开命令窗口,切换到mysql安装目录 可以在控制台目录切换,也可以打开所在安装目录后再打开控制台 2 . 执行命令:mysql -u root -p 3 . 无法访问的话,查看防火墙 ...

  2. 在azure windows虚拟机上安装iis

    在 dashboard-添加角色和功能-一直往下点就好了,后”选择安装类型“页面 中选择[基于角色或基于功能的安装],安装完成后 在浏览器输入 http://localhost/ 就可以正常访问网站了 ...

  3. 微信小程序:页面跳转时传递数据到另一个页面

    一.功能描述 页面跳转时,同时把当前页面的数据传递给跳转的目标页面,并在跳转后的目标页面进行展示 二.功能实现 1. 代码实现 test1页面 // pages/test1/test1.js Page ...

  4. hive 空值、NULL判断

    hive中空值判断基本分两种 (1)NULL 与 \N hive在底层数据中如何保存和标识NULL,是由 alter table name SET SERDEPROPERTIES('serializa ...

  5. 求两个字符串的最长公共子串——Java实现

    要求:求两个字符串的最长公共子串,如“abcdefg”和“adefgwgeweg”的最长公共子串为“defg”(子串必须是连续的) public class Main03{ // 求解两个字符号的最长 ...

  6. this指向问题(箭头函数没有this)

    全局环境下,指向windows console.log(this.document === document); // true 函数上下文调用 function f1(){ return this; ...

  7. 《Node.js核心技术教程》读书笔记---思维导图版

    书薄,挺经看!

  8. Python数据挖掘——数据预处理

    Python数据挖掘——数据预处理 数据预处理 数据质量 准确性.完整性.一致性.时效性.可信性.可解释性 数据预处理的主要任务 数据清理 数据集成 数据归约 维归约 数值归约 数据变换 规范化 数据 ...

  9. 《机器学习实战》6.2小节,KKT条件代码理解

    <机器学习实战>6.2小节 #这句是检测 当前样本点i 是否满足KKT条件的 if (alphas[i, :] < C and E_i * labelMat[i, :] < - ...

  10. PayPal接洽苹果 欲承接手机支付外包

    不久前,<华尔街日报>等媒体报道,苹果正计划利用iTunes内部支付功能,推出第三方手机支付服务.美国科技 新闻网站Recode1月30日引述消息人士称,移动支付领军厂商PayPal,目前 ...