网络最大流算法—Dinic算法及优化
前置知识
网络最大流入门
前言
Dinic在信息学奥赛中是一种最常用的求网络最大流的算法。
它凭借着思路直观,代码难度小,性能优越等优势,深受广大oier青睐
思想
$Dinic$算法属于增广路算法。
它的核心思想是:对于每一个点,对其所连的边进行增广,在增广的时候,每次增广“极大流”
这里有别于EK算法,EK算法是从边入手,而Dinic算法是从点入手
在增广的时候,对于一个点连出去的边都尝试进行增广,即多路增广
Dinic算法还引入了分层图这一概念,即对于$i$号节点,用$dis(i)$表示它到源点的距离,并规定,一条边能够被增广,当且仅当它连接的两个点$u,v$满足:$dis(v)=dis(u)+1$,这样可以大大优化其时间复杂度。
实现
有了上面的知识,Dinic实现起来也就比较简单了。
每次BFS构造分层图(注意必须每次都重新构造,因为每次增广之后会删除一些无用的边,也就会删除一些无用的点)
然后从源点开始多路增广
优化
- 当前弧优化:对于每个点,我们记录下它已经增广了哪些边,当再次回到这个点的时候,无视已经增广过的边,从下一条边开始增广
- 分层优化(自己xjb起的名字):在进行分层的时候,找到汇点立即退出
- 剩余量优化(也是自己起的):在进行增广的时候,如果该节点已经没有流量,直接退出
时间复杂度
Dinic算法的理论时间复杂度为$O(n^2*m)$
证明可以看这里
但是!
Dinic算法的性能在比赛中表现的非常优越。
按照集训队大佬ly的说法,我们可以认为Dinic算法的时间复杂度是线性的(比某标号算法不知道高到哪里去了)
代码
#include<cstdio>
#include<cstring>
#include<queue>
#define AddEdge(x,y,z) add_edge(x,y,z),add_edge(y,x,0);
using namespace std;
const int MAXN=1e6+;
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;
struct node
{
int v,flow,nxt;
}edge[MAXN*];
int head[MAXN],cur[MAXN],num=;//注意这里必须从0开始
inline void add_edge(int x,int y,int z)
{
edge[num].v=y;
edge[num].flow=z;
edge[num].nxt=head[x];
head[x]=num++;
}
int deep[MAXN],q[MAXN];
inline bool BFS()
{
memset(deep,,sizeof(deep));
deep[S]=;
int l=,r=;
q[++l]=S;
while(l<=r)
{
int p=q[l++];
for(int i=head[p];i!=-;i=edge[i].nxt)
if(!deep[edge[i].v]&&edge[i].flow)
{
deep[edge[i].v]=deep[p]+;q[++r]=edge[i].v;
if(edge[i].v==T) return ;//当找到汇点的时候直接返回 快30ms
}
}
return deep[T];
}
int DFS(int now,int nowflow)
{
if(now==T) return nowflow;
int totflow=;//从这个点总共可以增广多少流量
for(int i=head[now];i!=-;i=edge[i].nxt)//当前弧优化 快150ms
{
if(deep[edge[i].v]==deep[now]+&&edge[i].flow)//只有满足距离要求与流量要求的点才能进行增广
{
int canflow=DFS(edge[i].v,min(nowflow,edge[i].flow));
edge[i].flow-=canflow;edge[i^].flow+=canflow;//增广
totflow+=canflow;
nowflow-=canflow;
if(nowflow<=) break; //当前点已经没有流量 快100ms
}
}
return totflow;
}
void Dinic()
{
int ans=;
while(BFS())//每次构造分层图
{
memcpy(cur,head,sizeof(head)); //当前弧优化
ans+=DFS(S,INF);//进行增广
}
printf("%d",ans);
}
int main()
{
#ifdef WIN32
freopen("a.in","r",stdin);
#else
#endif
N=read();M=read();S=read();T=read();
memset(head,-,sizeof(head));
for(int i=;i<=M;i++)
{
int x,y,z;
x=read();y=read();z=read();
AddEdge(x,y,z);
}
Dinic();
return ;
}
网络最大流算法—Dinic算法及优化的更多相关文章
- POJ 1459 Power Network(网络最大流,dinic算法模板题)
题意:给出n,np,nc,m,n为节点数,np为发电站数,nc为用电厂数,m为边的个数. 接下来给出m个数据(u,v)z,表示w(u,v)允许传输的最大电力为z:np个数据(u)z,表示发电 ...
- 网络流入门—用于最大流的Dinic算法
"网络流博大精深"-sideman语 一个基本的网络流问题 最早知道网络流的内容便是最大流问题,最大流问题很好理解: 解释一定要通俗! 如右图所示,有一个管道系统,节点{1,2,3 ...
- 浅谈最大流的Dinic算法
PART 1 什么是网络流 网络流(network-flows)是一种类比水流的解决问题方法,与线性规划密切相关.网络流的理论和应用在不断发展,出现了具有增益的流.多终端流.多商品流以及网络流的分解与 ...
- 【最大流之Dinic算法】POJ1273 【 & 当前弧优化 & 】
总评一句:Dinic算法的基本思想比较好理解,就是它的当前弧优化的思想,网上的资料也不多,所以对于当前弧的优化,我还是费了很大的功夫的,现在也一知半解,索性就写一篇博客,来发现自己哪里的算法思想还没理 ...
- 最大流EK算法/DINIC算法学习
之前一直觉得很难,没学过网络流,毕竟是基础知识现在重新来看. 定义一下网络流问题,就是在一幅有向图中,每条边有两个属性,一个是cap表示容量,一个是flow 表示流过的流量.我们要求解的问题就是从S点 ...
- [学习笔记] 网络最大流的HLPP算法
#define \(u\)的伴点集合 与\(u\)相隔一条边的且\(u\)能达到的点的集合 \(0x00~ {}~Preface\) \(HLPP(Highest~Label~Preflow~Push ...
- 【网络流相关】最大流的Dinic算法实现
Luogu P3376 于\(EK\)算法求最大流时每一次只求一条增广路,时间复杂度会比较高.尽管实际应用中表现比较优秀,但是有一些题目还是无法通过. 那么我们就会使用\(Dinic\)算法实现多路增 ...
- 一般增广路方法求网络最大流(Ford-Fulkerson算法)
/* Time:2015-6-18 接触网络流好几天了 写的第一个模版————Ford-Fulkerson算法 作用:求解网络最大流 注意:源点是0 汇点是1 如果题目输入的是1到n 请预处理减1 * ...
- HDU1532最大流 Edmonds-Karp,Dinic算法 模板
Drainage Ditches Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) To ...
随机推荐
- Java SpringMvc Jar包下载及部署方式_转载
本次来记录一下关于 springmvc jar包的下载以及部署 首先登陆 http://repo.spring.io/release/org/springframework/spring/到里面我 ...
- Mojom IDL and Bindings Generator
Mojom IDL and Bindings Generator This document is a subset of the Mojo documentation. Contents Overv ...
- ES6学习笔记(十二)异步解决方案Promise
1.Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了P ...
- luoguP1419 寻找段落(二分答案+单调队列)
题意 给定一个长度为n的序列a1~an,从中选取一段长度在s到t之间的连续一段使其平均值最大.(n<=100000) 题解 二分答案平均值. judge时把每一个a[i]-mid得到b[i] 在 ...
- poj 3613 Cow Relays(矩阵的图论意义)
题解 用一个矩阵来表示一个图的边的存在性,即矩阵C[i,j]=1表示有一条从i到j的有向边C[i,j]=0表示没有从i到j的边.这个矩阵的k次方后C[i,j]就表示有多少条从i到j恰好经过k条边的路径 ...
- 对GPDB查询计划的Motion结点的理解
GPDB在进行join查询时,可能会产生Motion结点 根据官方文档,总共有这几种Motion: redistribute 重分布(用hash取模的方法把join字段重分布到各个segment,相当 ...
- 火狐不支持innerText属性,只支持innerHTML属性
做的一个js的小程序放到火狐上用不了了,原因是innerText不是标准属性,换成innerHTML属性就好,但是可能需要把html标签给去掉
- hdu 1695 GCD (欧拉函数、容斥原理)
GCD Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- webpack03
index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- spring-cloud-netflix集成的服务
1.Ribbon Ribbon is a client side IPC library that is battle-tested in cloud. It provides the followi ...