Dinic是优化的EK
Dinic算法的流程是,每次寻找可行流路径的时候都先通过一次bfs给原网络分层(如果不能分层,那么已经是最大流网络了),再通过dfs给分层后的网络找可行流路径(这时候不是仅仅找一条,二十一次dfs可以找许多条可行流)。
(图片来源:https://www.cnblogs.com/LUO77/p/6115057.html)
这里六张图是在若干次寻找增广路之后的中间形态。
图a是起始情况,图b分层,用bfs抽出一个分层子图出来。经过第一次dfs得到图c的,经过第二次dfs得到图e,每次dfs得到一条增广路,第三次dfs发现不能达到汇点,这个分层子图就已经不能分层了(源点不能够达到汇点)。
然后我们就完成了一个阶段的增广。重复上述过程:一次bfs+多次dfs就可找到所有的增广路。
code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int num=0;char c=' ';bool flag=true;
for(;c>'9'||c<'0';c=getchar())
if(c=='-')
flag=false;
for(;c>='0'&&c<='9';num=(num<<3)+(num<<1)+c-48,c=getchar());
return flag ? num : -num;
}
const int maxn=10020;
const int maxm=100020;
namespace graph{
struct node{
int dot,val,next;
}a[maxm*2];
int n,m,s,t;
int head[maxn],top=0;
void insert(int x,int y,int v){
a[top].dot=y;
a[top].val=v;
a[top].next=head[x];
head[x]=top++;
}
void init(){
n=read();
m=read();
s=read();
t=read();
memset(head,-1,sizeof head);
for(int i=1;i<=m;i++){
int x=read();
int y=read();
int v=read();
insert(x,y,v);
insert(y,x,0);
}
}
}using namespace graph;
namespace Flow{
int d[maxn];
bool bfs(){
memset(d,0,sizeof d);
queue<int>q;
q.push(s);d[s]=1;//d即深度,也就是层次
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=head[x];i!=-1;i=a[i].next){
int y=a[i].dot;
if(a[i].val&&!d[y]){
q.push(y);
d[y]=d[x]+1;
if(y==t)return true;
}
}
}
return false;
}
int dfs(int x,int flow){
//当前在哪个点、当前的流量
if(x==t)
return flow;
for(int i=head[x];i+1;i=a[i].next){
int y=a[i].dot;
if(d[y]==d[x]+1 && a[i].val!=0){
int k=dfs(y,min(a[i].val,flow));
//这里的参数值得注意。
//我们往水管里通水的限制因素由两个
//我们拥有的水量和水管粗细
if(k){
a[i].val-=k;
a[i^1].val+=k;
return k;
}
}
}
return 0;
}
//每次dfs只找出一条可行流路径
}using namespace Flow;
const int INF=2e9;
void dinic(){
int flow=0;
int maxflow=0;
while(bfs())
while(flow=dfs(s,INF))maxflow +=flow;
//一次bfs带动多次可行流路径
printf("%d\n",maxflow);
}
int main(){
init();
dinic();
return 0;
}
时间复杂度
O(n2×m) O ( n 2 × m ) ,但实际应用中这是一个很松的上界。一般可以处理 104 10 4 到 105 10 5 的网络