初学dinic算法,带上洛谷p3376,谈谈自己的一点理解和看法

题目:从头裸到脚的最大流(dinic)

对于dinic我自己也在网上找了许多博客看了一下,都写得挺不错,但是有一些博客会有小小得错误,我这里提醒一下。

就是在拿EK 算法 和 dinic 算法对比的时候,会用这幅图:

说使用EK可能程序会顺着 A -> B -> C-> D ,A -> C ->B ->D 两条路线不断更新,这样就很慢

其实因为EK是一个BFS,本质上是寻找最短增广路然后不断更新,这个例子里面最短路是A->B->D 和 A->C->D ,无论如何都选不到bc这条线。

但是用来理解是极好的,我一开始也是看着这副图恍然大悟。

其实dinic算法就是:

1.使用bfs对图进行分层(层取决于点到源点的最短距离)

2.靠着bfs分的层来跑dfs,有了bfs的层的指导能让dfs的效率大大增加(dfs只能往深层走不能到同一层或者浅层),然后dfs可以一次性更新一大片的流,看图:

(蓝色数字表示访问顺序)

跑一次dfs就可以更新一大片,不需要EK每次都要重头来过,我觉得这是快的主要原因(个人看法而已)

3.等到dfs跑完,没办法跑dfs的时候,此时有两种可能,第一种是:从源点到汇点的路径中需要经过同层或者返回上一层,第二种就是跑完了

4.因此再跑一次bfs,重新分层,分的了层就回到1,分不了层就说明游戏结束。

看代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=210000+10; //有负边开多一倍啊混蛋 
struct edge{
	int to,val,next;
}edges[maxn];
const int INF=0x3f3f3f3f;
int head[10005],deep[10005]; 
int N,M,S,T;
int DFS(int point,int flow){ //flow 应该表示v点以前flow最小值 
	if(point==T) return flow;
	int sto=head[point],total_flow=0,_flow=0; 
	while(sto!=-1){
		int aim=edges[sto].to; 
		if(deep[aim]==deep[point]+1&&edges[sto].val){ //走下一层 
			_flow=DFS(aim,min(flow,edges[sto].val));
			flow-=_flow; //这句这句 
			edges[sto].val-=_flow;
			edges[sto+1].val+=_flow;
			total_flow+=_flow;
			if(flow==0) break; 
		}
		sto=edges[sto].next;
	}
	if(total_flow==0) deep[point]=-1;
	return total_flow;
}
bool BFS(){
	memset(deep,-1,sizeof(deep));
	queue<int> Q;
	Q.push(S);
	deep[S]=0;
	while(!Q.empty()){
		int now=Q.front();  Q.pop();
		int sto=head[now];
		while(sto!=-1){
			if(deep[edges[sto].to]==-1&&edges[sto].val){ //没有被更新过+可以走才进♂来啊 
				deep[edges[sto].to]=deep[now]+1;//深度+推进 
				Q.push(edges[sto].to);
				if(edges[sto].to==T) return 1;
				 
			}
			sto=edges[sto].next;
		}
	}
	return 0; 
}
void dinic(){
	int ans=0;
	while(BFS()){
		ans+=DFS(S,INF);
	}
	cout<<ans;
}
int main(){
	cin>>N>>M>>S>>T;
	int ind=0;
	memset(head,-1,sizeof(head));
	for(int i=1;i<=M;i++){
		int fro,to,val; scanf("%d %d %d",&fro,&to,&val);
		edges[++ind].to=to;
		edges[ind].val=val;
		edges[ind].next=head[fro];
		head[fro]=ind;
		edges[++ind].to=fro; //相反边的index必然是正边+1 
		edges[ind].val=0;
		edges[ind].next=head[to];
		head[to]=ind;
	}
	dinic();
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_43191865/article/details/88604415
今日推荐