算法_dinic最大流
Posted ezoihy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法_dinic最大流相关的知识,希望对你有一定的参考价值。
网络流是什么?
不急我们慢慢来讲。
首先我们先看看最大流
1.背景
管道网络中每条边的最大通过能力(容量)是有限的,实际流量不超过容量。最大流问题(maximum flow problem),一种组合最优化问题,就是要讨论如何充分利用装置的能力,使得运输的流量最大,以取得最好的效果。求最大流的标号算法最早由福特和福克逊与与1956年提出,20世纪50年代福特(Ford)、(Fulkerson)建立的“网络流理论”,是网络应用的重要组成成分。
2.定义(这很重要!!!)
1)源点:只有流出去的点
2)汇点:只有流进来的点
3)流量:一条边上流过的流量
4)容量:一条边上可供流过的最大流量
5)残量:一条边上的容量-流量
2.性质
1)对于任何一条流,总有流量<=容量(流经的边的最小流量),即
[flow<=min left{cur_{i}
ight}(cur_iin flow_{now})]
2)对于任何一条有向边(u,v),总有
[cur(u,v)=-cur(v,u)]
3.算法思想(增广路dinic)
1.找到一条从源点到汇点的路径,使得路径上任意一条边的残量>0(注意是小于而不是小于等于,这意味着这条边还可以分配流量),这条路径便称为增广路
2.找到这条路径上最小的(F[u][v])(我们设(F[u][v])表示(u->v)这条边上的残量即剩余流量),下面记为(flow)
3.将这条路径上的每一条有向边(u->v)的残量减去(flow),同时对于起反向边(v->u)的残量加上(flow)(为什么呢?我们下面再讲)
4.重复上述过程,直到找不出增广路,此时我们就找到了最大流
这个图很详细的给出了增广路的过程,其实这就是dinic算法的思想
4.时间复杂度
dinic算法其实就是一种暴力,时间复杂度
[O(n^2m)]
这其实十分暴力了,如果(m=frac{n(n-1)}{2})d的话,那么时间复杂度将达到
[O(frac{n^3(n-1)}{2})]
省略常数后也就是
[O(n^4)]
这是极其恐怖的复杂度,当然如果出题人不故意卡的话,一般没什么问题
5.代码实现
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define Maxn 1000001
#define INF 0x7fffffff
#define maxN 1000001
#define maxM 1000001
using namespace std;
class Dinic{
private:
int cnt;//边的数量,从0开始编号。
int head[Maxn];//每一个点最后一条边的编号
int next[Maxn];//指向对应点的前一条边
int v[Maxn];//每一条边指向的点
int w[Maxn];//每一条边的残量
int n,s,t;//源点和汇点
int depth[Maxn];//分层图中标记深度
void add_edge(int x,int y,int z){
next[++cnt]=head[x];
v[cnt]=y;
w[cnt]=z;
head[x]=cnt;
return;
}
public:
void init(int x,int y,int z){//初始化
n=x,s=y,t=z;
cnt=-1;
memset(head,-1,sizeof(head));
memset(next,-1,sizeof(next));
return;
}
void addedge(int x,int y,int z){
add_edge(x,y,z);
add_edge(y,x,0);
return;
}
bool bfs(){//广搜找分层图
queue<int>q;
memset(depth,0,sizeof(depth));
depth[s]=1;
q.push(s);
do{
int u=q.front();
q.pop();
for(int i=head[u];~i;i=next[i]){
if(w[i]>0 and !depth[v[i]]){
depth[v[i]]=depth[u]+1;
q.push(v[i]);
}
}
}while(!q.empty());
return depth[t];
}
int dfs(int u,int now){
if(u==t)
return now;
for(int i=head[u];~i;i=next[i]){
if(w[i]>0 and depth[v[i]]==depth[u]+1){
int d=dfs(v[i],min(now,w[i]));
if(d>0){
w[i]-=d;w[i^1]+=d;
return d;
}
}
}
return 0;
}
int dinic(){//dinic算法主过程
int ans=0;
while(bfs()){
int x;
while(x=dfs(s,INF))
ans+=x;
}
return ans;
}
}dinic;
int n,m,s,t;
int main(){
scanf("%d%d%d%d",&n,&m,&s,&t);
dinic.init(n,s,t);
for(int i=1;i<=m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
dinic.addedge(x,y,z);
}
printf("%d
",dinic.dinic());
return 0;
}
6.最大流能解决的问题
网络流的问题其实有着很大的共性,首先就是他们都是只需要求一个的答案,且不需要中间的过程,还有答案是某种最值,往往这就是网络流。而网络流也不是裸的,往往需要各种建模乱搞。
以上是关于算法_dinic最大流的主要内容,如果未能解决你的问题,请参考以下文章