昨天我们学习了ISAP算法,它属于增广路算法的大类。今天学习的算法是预流推进算法中很高效的一类——最高标号预流推进(HLPP)。

预流推进

预流推进是一种很直观的网络流算法。如果给到一个网络流让你手算,一般的想法是从源点开始流,遇到不够的就减掉,一直往前推到汇点。这就是预流推进算法的基本思想。

每个节点是一个储水池,最开始源点有无限多的水。用一个队列维护需要处理的点。最开始把源点加进去,对于每一个当前点,我们把将这个点水池中有的流量沿着边(水管)推到相邻的点,然后把相邻的点加入队列中。

算法思想如此,但其中有一个问题:这样做有可能出现两个点一个推过来一个推回去,结果就死循环了。这时候我们给每个点引入一个高度来解决这个问题。

源点的高度为\(n\),汇点的高度为\(0\),其他点初始高度为0,我们规定,水往下一层流,即我们只推\(h[x]=h[v]+1\)的边\((x,v)\)。

如果一个点还有水,但是却无法推出去,即周围的点都比他高,那么我们就抬高这个点,因为\(h\)值是连续的,所以每次出现这种情况我们就给它加一。如果这个点根本就流不出去,那么最后它会被抬高到\(n+1\)的高度,回流给源点。

最高标号

Tarjan和Goldberg在1986年提出了最高标号预留推进算法,即把普通队列换成优先队列,每次取出高度最高的那个来推进。Cheriyan和Maheshwari在1988年证明了这样做的复杂度为\(O(n^2\sqrt m)\)。

优化

喜闻乐见的gap优化,但和ISAP的形式不太一样。如果我们发现在给一个点抬高1的高度的时候,这个点原来的高度已经没有点了,那么我们直接把大于这个高度的点全部设为高度\(n+1\),让他们回流到源点去,因为根据算法,他们无法再有机会把水推到汇点(为什么不能有下面一个点抬上来形成路径呢?因为一个点的高度是所有相邻点高度最小值加一,所以不可能出现这种情况)。

代码

依然是poj1273模版题,然而poj今天好像挂了。hdu1532是同一题。

实测中ISAP跑得快,我估计是因为ISAP的复杂度上界非常松,而HLPP的上界是很紧的,导致ISAP随机下跑得超级快。

#include<cstdio>
#include<cstring>
#include<cctype>
#include<vector>
#include<queue>
#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=1e3+10;
const int maxm=1e6+10;
const int inf=2147483646;
vector<int> inv[maxn];
struct edge {
int v,w,nxt;
} e[maxm<<1];
int h[maxn],tot,d[maxn],n,m,prs[maxn],gap[maxn];
bool able[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;
}
struct cmp {
int x,h;
cmp (int x=0,int h=0):x(x),h(h) {}
inline bool operator < (const cmp &a) const {return h<a.h;}
};
priority_queue<cmp> pq;
bool push(int x,int y,int p) {
int w=min(prs[x],e[p].w);
e[p].w-=w,e[p^1].w+=w,prs[x]-=w,prs[y]+=w;
return w;
}
void Gap(int l,int s,int t) {
for (int i=1;i<=n;++i) if (i!=s && i!=t && l<d[i] && d[i]<=n) d[i]=n+1;
}
int maxflow(int s,int t) {
while (!pq.empty()) pq.pop();
memset(prs,0,sizeof prs),memset(d,0,sizeof d),memset(gap,0,sizeof gap);
d[s]=n,prs[s]=inf,pq.push(cmp(s,d[s]));
while (!pq.empty()) {
int x=pq.top().x;
pq.pop();
if (!prs[x]) continue;
for (int i=h[x],v=e[i].v;i;i=e[i].nxt,v=e[i].v) if ((x==s || d[x]==d[v]+1) && push(x,v,i) && v!=t && v!=s) pq.push(cmp(v,d[v]));
if (x!=s && x!=t && prs[x]) {
if (!(--gap[d[x]])) Gap(d[x],s,t);
++gap[++d[x]];
pq.push(cmp(x,d[x]));
}
}
return prs[t];
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
freopen("my.out","w",stdout);
#endif
while (~scanf("%d%d",&m,&n)) {
memset(h,0,sizeof h),tot=1;
for (int i=1;i<=m;++i) {
int x=read(),y=read(),w=read();
if (!w) continue;
add(x,y,w);
}
int ans=maxflow(1,n);
printf("%d\n",ans);
}
return 0;
}

最大流算法-最高标号预流推进(HLPP)的更多相关文章

  1. 网络最大流算法—最高标号预流推进HLPP

    吐槽 这个算法.. 怎么说........ 学来也就是装装13吧.... 长得比EK丑 跑的比EK慢 写着比EK难 思想 大家先来猜一下这个算法的思想吧:joy: 看看人家的名字——最高标号预留推进 ...

  2. ZOJ-2364 Data Transmission 分层图阻塞流 Dinic+贪心预流

    题意:给定一个分层图,即只能够在相邻层次之间流动,给定了各个顶点的层次.要求输出一个阻塞流. 分析:该题直接Dinic求最大流TLE了,网上说采用Isap也TLE,而最大流中的最高标号预流推进(HLP ...

  3. 最大流算法-ISAP

    引入 最大流算法分为两类,一种是增广路算法,一种是预留推进算法.增广路算法包括时间复杂度\(O(nm^2)\)的EK算法,上界为\(O(n^2m)\)的Dinic算法,以及一些其他的算法.EK算法直接 ...

  4. 最大流算法之ISAP

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

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

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

  6. Ford-Fulkerson 最大流算法

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

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

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

  8. 图论算法-最小费用最大流模板【EK;Dinic】

    图论算法-最小费用最大流模板[EK;Dinic] EK模板 const int inf=1000000000; int n,m,s,t; struct node{int v,w,c;}; vector ...

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

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

随机推荐

  1. 洛谷 P1057 传球游戏 解题报告

    P1057 传球游戏 题目描述 上体育课的时候,小蛮的老师经常带着同学们一起做游戏.这次,老师带着同学们一起做传球游戏. 游戏规则是这样的:n个同学站成一个圆圈,其中的一个同学手里拿着一个球,当老师吹 ...

  2. luogu3645 [Apio2015]雅加达的摩天大楼 (分块+dijkstra)

    我们是想跑最短路的 我们有两种建图方式: 1.对于每个doge i,连向B[j]==B[i]+P[i]*k ,k=..,-2,-1,0,1,2,... ,边权=|k|,这样连的复杂度是$O(N\sum ...

  3. 面试 -- requestLayout、invalidate与postInvalidate区别

    requestLayout: 从方法名字可以知道,“请求布局”,那就是说,如果调用了这个方法,那么对于一个子View来说,应该会重新进行布局流程.但是,真实情况略有不同,如果子View调用了这个方法, ...

  4. 【Linux】fg、bg让你的进程在前后台之间切换

    Linux下的fg和bg命令是进程的前后台调度命令,即将指定号码(非进程号)的命令进程放到前台或后台运行.比如一个需要长时间运行的命令,我们就希望把它放入后台,这样就不会阻塞当前的操作:而一些服务型的 ...

  5. Codeforces Round #548

    没打,简单补档 C.Edgy Trees 容斥,把黑边断掉数联通块,每个联通块贡献$siz^k$ #include<cstdio> #include<cstring> #inc ...

  6. Kafka配置文件server.properties(三个版本)

    前言 其实每个版本都有些许改动,只不过改动大小而已,但是网上的教程都真的太老了,其实更新一下也费不了多少时间 0.9.0 # Licensed to the Apache Software Found ...

  7. 关于Picasso load本地图片显示失败的探究

    今天测试找过来说图片不显示了,查了一下是Picasso加载本地图片没有显示,奇怪了,以前都是这样写为什么现在不行了,难道是Picasso有bug了,怀着激动的心情断点跟进去发现 Picasso所有lo ...

  8. 十、java_IO

    目录: 一.java流式输入/输出原理 二.java流类的分类 三.输入/输出流类 四.常见的节点流和处理流 五.文件流 六.缓冲流 七.数据流 八.转换流 九.Print流 十.Ubject流 一. ...

  9. 源码研究:php变量

    一:php中的变量类型 1.标量类型:布尔型 bool,整型 int,浮点型 float,字符串型 string2.复杂类型:数组 array,对象 object3.特殊类型:NULL,资源 reso ...

  10. loadrunner之WebServices协议脚本编写(三种请求模式)

    以天气预报网站为例:http://www.webxml.com.cn/WebServices/WeatherWebService.asmx?wsdl 一.web_service_call模式 步骤如下 ...