网络最大流算法—最高标号预流推进HLPP
吐槽
这个算法。。
怎么说........
学来也就是装装13吧。。。。
长得比EK丑
跑的比EK慢
写着比EK难
思想
大家先来猜一下这个算法的思想吧:joy:
看看人家的名字——最高标号预留推进
多么高端大气上档次2333333咳咳
从它的名字中我们可以看出,它的核心思想是—推进,而不是找增广路
那么它是怎么实现推进的呢?
很简单,我们从源点开始,不停的向其他的点加流量,对于每个点都如此操作。那么推到最后,我们就可以得到到达汇点的最大流量
不过可能会出现一种情况,就是$A$送流量给$B$,$B$觉得不好意思不想要,于是又推给$A$,$A$非常热情便又推给$B$……直到推到TLE为止。。那怎么解决这种情况呢?
我们对每个点,引入一个高度$H$,并且规定,一个点$u$可以向另一个点$v$送流量,当且仅当$H[u]=H[s]+1$
这样我们就可以保证不会有上面情况发生了
另外还有一种情况,就是这个点依然有流量,但是迫于高度的限制流不出去,那怎么办呢?
很简单,我们增加这个点的高度,这样这个点的流量就能流出去了。
优化
预留推进也就是这些内容了
但是它的名字里的最高标号是啥意思呢?
这个要感谢咱们的熟人tarjan,他和他的小伙伴发现,如果每次选的点是高度最高的点,时间复杂度会更优。
可以优化至$O(n^2\sqrt{m})$
另外还有一个比较显然的优化,如果一个高度$i$是不存在的,即图中没有高度为$i$的点,那么从比$i$高的点一定不会走到汇点$T$,因为根据我们的限制条件,必须要经过高度为$i$的点,于是这些点就没有用了
代码
不是我说,这个算法真的是死慢死慢的,,,,
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int MAXN=*1e3+;
const int INF=1e8+;
inline char nc()
{
static char buf[MAXN],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
char c=nc();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=nc();}
while(c>=''&&c<=''){x=x*+c-'';c=nc();}
return x*f;
}
int N,M,S,T;
int H[MAXN];//每个节点的高度
int F[MAXN];//每个节点可以流出的流量
int gap[MAXN];//每个高度的数量
struct node
{
int u,v,flow,nxt;
}edge[MAXN];
int head[MAXN];
int num=;//注意这里num必须从0开始
inline void add_edge(int x,int y,int z)
{
edge[num].u=x;
edge[num].v=y;
edge[num].flow=z;
edge[num].nxt=head[x];
head[x]=num++;
}
inline void AddEdge(int x,int y,int z)
{
add_edge(x,y,z);
add_edge(y,x,);//注意这里别忘了加反向边
}
struct comp
{
int pos,h;
comp(int pos=,int h=):pos(pos),h(h) {}
inline bool operator < (const comp &a) const {return h<a.h;}
};
priority_queue<comp>q;
bool Work(int u,int v,int id)
{
int val=min(F[u],edge[id].flow);
edge[id].flow-=val;edge[id^].flow+=val;
F[u]-=val;F[v]+=val;
return val;
}
inline int HLPP()
{
H[S]=N;F[S]=INF;q.push(comp(S,H[S]));
while(q.size()!=)
{
int p=q.top().pos;q.pop();
if(!F[p]) continue;
for(int i=head[p];i!=-;i=edge[i].nxt)
if( (p==S||H[edge[i].v]+==H[p]) && Work(p,edge[i].v,i) && edge[i].v!=S && edge[i].v!=T)
q.push( comp(edge[i].v,H[edge[i].v]) );
if(p!=S && p!=T && F[p])
{
if( (--gap[ H[p] ])== )//该高度不存在
{
for(int i=;i<=N;i++)
if( H[p]<H[i]&&H[i]<=N && p!=S && p!=T )
H[i]=N+;//设置为不可访问
}
++gap[ ++H[p] ];//高度+1
q.push( comp(p,H[p]) );
}
}
return F[T];
}
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
memset(head,-,sizeof(head));
N=read(),M=read(),S=read(),T=read();
for(int i=;i<=M;i++)
{
int x=read(),y=read(),z=read();
AddEdge(x,y,z);
}
printf("%d", HLPP() );
return ;
}
网络最大流算法—最高标号预流推进HLPP的更多相关文章
- 最大流算法-最高标号预流推进(HLPP)
昨天我们学习了ISAP算法,它属于增广路算法的大类.今天学习的算法是预流推进算法中很高效的一类--最高标号预流推进(HLPP). 预流推进 预流推进是一种很直观的网络流算法.如果给到一个网络流让你手算 ...
- ZOJ-2364 Data Transmission 分层图阻塞流 Dinic+贪心预流
题意:给定一个分层图,即只能够在相邻层次之间流动,给定了各个顶点的层次.要求输出一个阻塞流. 分析:该题直接Dinic求最大流TLE了,网上说采用Isap也TLE,而最大流中的最高标号预流推进(HLP ...
- 最大流算法-ISAP
引入 最大流算法分为两类,一种是增广路算法,一种是预留推进算法.增广路算法包括时间复杂度\(O(nm^2)\)的EK算法,上界为\(O(n^2m)\)的Dinic算法,以及一些其他的算法.EK算法直接 ...
- 常用限流算法与Guava RateLimiter源码解析
在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...
- Ford-Fulkerson 最大流算法
流网络(Flow Networks)指的是一个有向图 G = (V, E),其中每条边 (u, v) ∈ E 均有一非负容量 c(u, v) ≥ 0.如果 (u, v) ∉ E 则可以规定 c(u, ...
- 算法9-5:最大流算法的Java代码
残留网络 在介绍最大流算法之前先介绍一下什么是残留网络.残余网络的概念有点类似于集合中的补集概念. 下图是残余网络的样例. 上面的网络是原始网络.以下的网络是计算出的残留网络.残留网络的作用就是用来描 ...
- 最大流算法之ISAP
序: 在之前的博文中,我解释了关于最大流的EK与Dinic算法,以及它们的STL/非STL的实现(其实没什么区别).本次讲解的是ISAP算法.'I',指 inproved,也就是说ISAP其实是SAP ...
- 最大流算法之Ford-Fulkerson算法与Edmonds–Karp算法
引子 曾经很多次看过最大流的模板,基础概念什么的也看了很多遍.也曾经用过强者同学的板子,然而却一直不会网络流.虽然曾经尝试过写,然而即使最简单的一种算法也没有写成功过,然后对着强者大神的代码一点一点的 ...
- coding++:RateLimiter 限流算法之漏桶算法、令牌桶算法--简介
RateLimiter是Guava的concurrent包下的一个用于限制访问频率的类 <dependency> <groupId>com.google.guava</g ...
随机推荐
- .NET Core跨平台的奥秘[下篇]:全新的布局
从本质上讲,按照CLI规范设计的.NET从其出生的那一刻就具有跨平台的基因,这与Java别无二致.由于采用了统一的中间语言,微软只需要针对不同的平台设计不同的虚拟机(运行时)就能弥合不同操作系统与处理 ...
- MySQL 使用自增ID主键和UUID 作为主键的优劣比较详细过程(从百万到千万表记录测试)
测试缘由 一个开发同事做了一个框架,里面主键是uuid,我跟他建议说mysql不要用uuid用自增主键,自增主键效率高,他说不一定高,我说innodb的索引特性导致了自增id做主键是效率最好的,为了拿 ...
- [Swift]LeetCode212. 单词搜索 II | Word Search II
Given a 2D board and a list of words from the dictionary, find all words in the board. Each word mus ...
- [Swift]LeetCode247.对称数 II $ Strobogrammatic Number II
A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside ...
- 老司机教你用原生JDK 撸一个 MVC 框架!!!
其实 Spring MVC 是一个基于请求驱动的 Web 框架,并且也使用了前端控制器模式来进行设计,再根据请求映射规则分发给相应的页面控制器进行处理,具体工作原理见下图. 在这里,就不详细谈相关的原 ...
- VSphere虚拟化ESXi的安装及基本管理
虚拟化和云计算技术正在快速的发展,新的概念.观点.产品不断涌现.服务器虚拟化技术受到了人们的高度重视,普遍相信虚拟化将成为数据中心的重要组成部分.vSphere是VMware公司推出的一套服务器虚拟化 ...
- 3-4 计算属性的setter和getter
Vue中的计算属性的setter和getter //如上,fullName这个方法在取这个数据的时候,会执行get中的方法:而在设置数据时,会执行set中的方法.其中set中有个参数(value),用 ...
- JavaScript03-基本概念一
js包括:语法.语句.类型.关键字.保留字.操作符和对象. 语法.关键字.保留字 1.js中一切区分大小写,包括变量.函数名.操作符: 2.标识符规则,第一个字符必须是字母.下划线_.或者美元符号,其 ...
- centos7中安装、配置、验证、卸载redis
本文介绍在centos7中安装.配置.验证.卸载redis等操作,以及在使用redis中的一些注意事项. 一 安装redis 1 创建redis的安装目录 利用以下命令,切换到/usr/local路径 ...
- Java异常处理:给程序罩一层保险
文/沉默王二 人这一生,总会遇到一些不可预料的麻烦,这些麻烦可能会让我们遭受沉重的打击.为了减轻因此承受的负担,我们就会买保险. 本着负责任的态度,我们程序员在写代码的时候,都非常的严谨.但程序在运行 ...