引入

最大流算法分为两类,一种是增广路算法,一种是预留推进算法。增广路算法包括时间复杂度\(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. 【SQLSERVER】索引的维护优化

    一.索引的利弊   优点: 1.大大加快数据的检索速度: 2.创建唯一性索引,保证数据库表中每一行数据的唯一性: 3.加速表和表之间的连接: 4.在使用分组和排序子句进行数据检索时,可以显著减少查询中 ...

  2. day 13 字典dict 操作

    1.len   键值对的个数 In [4]: nums = [11,22,33] In [6]: len(nums) Out[6]: 3 In [7]: infor = {"name&quo ...

  3. 【LOJ121】「离线可过」动态图连通性

    [LOJ121]「离线可过」动态图连通性 题面 LOJ 题解 线段树分治的经典应用 可以发现每个边出现的时间是一个区间 而我们每个询问是一个点 所以我们将所有边的区间打到一颗线段树上面去 询问每个叶子 ...

  4. C#目录:藏锋

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 此为C#专题的分类,只会记录我对于C#一些需求的解决方案,并非全部学习资料(全部可以参考微软提供的API) 主 ...

  5. nmap保存结果

    nmap 192.168.0.2 -oX D:\myscan.xml 参数解释: -oN <filespec> (标准输出) -oX <filespec> (XML输出) -o ...

  6. Appium+python HTML测试报告(1)(转)

    (原文:https://www.cnblogs.com/fancy0158/p/10054632.html) 测试任务执行完成后,我们需要一份通俗易懂的测试报告来展示自动化测试的结果. HTMLTes ...

  7. Jenkins Git安装设置

    Jenkins Git安装设置 在此安装中,必须确保Internet连接可连接其安装 Jenkins 机器.在 Jenkins 仪表盘(主屏幕)的左侧单击 Manage Jenkins 选项.打开网址 ...

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

    书薄,挺经看!

  9. Action Required: Listings Deactivated for Potential Pricing Error

    Dear Seller, We are contacting you because we have detected potential pricing errors in your Amazon. ...

  10. 欢迎来怼第二周Scrum会议六(总第十三次)

    一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华 小组照片 二.开会信息 时间:2017/10/25  17:19~17:35(总计16min).地点:东 ...