Drainage Ditches(最大流)

Drainage Ditches(最大流)

传送门

思路:最大流的裸题,此题数据较小,用EdmondsKarpEdmonds-Karp算法较方便。


第一次写记录一下算法的实现:

增广路径:从源点(类似起点)到汇点(类似终点) 的一条可行流的路径。

1.寻找增广路径并记录增广路径,找到在该路径上的最大流。

2.加上该贡献,然后对其路径建立反路径, (保证有反悔性质的贪心,得到最优解。)

3.直到找不到增广路径推出循环,返回总贡献值。


时间复杂度:O(nm2)O(nm^2),n,mn,m分别为结点数,边数。

复杂度证明:因为bfsbfs一次,需要O(m)O(m)的复杂度,总共需要bfs O(nm)bfs\ O(nm)次。

所以时间复杂度为:O(nm2)O(nm^2)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=205,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first 
#define se second
int n,m,st,ed,pre[N],g[N][N];	//pre[i] 记录路径. 
int bfs(){	//求增广路的最大流速. 
	int flow[N];	//保存流速. 
	mst(pre);
	queue<int>q;
	q.push(st);
	flow[st]=inf;
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=1;i<=n;i++){
			if(i!=st&&g[u][i]&&!pre[i]){
				pre[i]=u;
				q.push(i);
				flow[i]=min(flow[u],g[u][i]);
			}
		}
	}
	return pre[ed]?flow[ed]:-1;
}
int EK_flow(){
	int ans=0;
	while(1){
		int flow=bfs();
		if(flow==-1) break;//没有增广路说明当前已经是最大流. 
		int now=ed;
		while(now!=st){
			int fa=pre[now];
			g[fa][now]-=flow;
			g[now][fa]+=flow;	//重点:对残留网络建立反向路径 
			now=fa;
		}
		ans+=flow;
	}
	return ans;
}
int main(){
	while(~scanf("%d%d",&m,&n)){
		mst(g);
	for(int i=1;i<=m;i++){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		g[u][v]+=w;	//重边要将流速叠加起来 
	}
	st=1,ed=n;
	printf("%d\n",EK_flow());
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章