poj 1273 最大流(三種方法)

Drainage Ditches
Time Limit: 1000MS Memory Limit: 10000K
Total Submissions: 82153 Accepted: 31914

Description

Every time it rains on Farmer John's fields, a pond forms over Bessie's favorite clover patch. This means that the clover is covered by water for awhile and takes quite a long time to regrow. Thus, Farmer John has built a set of drainage ditches so that Bessie's clover patch is never covered in water. Instead, the water is drained to a nearby stream. Being an ace engineer, Farmer John has also installed regulators at the beginning of each ditch, so he can control at what rate water flows into that ditch.
Farmer John knows not only how many gallons of water each ditch can transport per minute but also the exact layout of the ditches, which feed out of the pond and into each other and stream in a potentially complex network.
Given all this information, determine the maximum rate at which water can be transported out of the pond and into the stream. For any given ditch, water flows in only one direction, but there might be a way that water can flow in a circle.

Input

The input includes several cases. For each case, the first line contains two space-separated integers, N (0 <= N <= 200) and M (2 <= M <= 200). N is the number of ditches that Farmer John has dug. M is the number of intersections points for those ditches. Intersection 1 is the pond. Intersection point M is the stream. Each of the following N lines contains three integers, Si, Ei, and Ci. Si and Ei (1 <= Si, Ei <= M) designate the intersections between which this ditch flows. Water will flow through this ditch from Si to Ei. Ci (0 <= Ci <= 10,000,000) is the maximum rate at which water will flow through the ditch.

Output

For each case, output a single integer, the maximum rate at which water may emptied from the pond.

Sample Input

5 4
1 2 40
1 4 20
2 4 20
2 3 30
3 4 10

Sample Output

50

題意:給你一個有向圖,每條邊都存在他自己的最大流量,1爲源點m爲匯點,問從源點出發到匯點,在匯點最大可以得到的流量是多少。

題解:最大流模板題,本蒟蒻不才,看了奆佬的博客(點擊打開鏈接)才勉強明白了這種題怎麼做的,一共三種方法,分別爲EK(bfs),FF(dfs),Dinic(bfs+dfs),最好都看看才能明白其中的奧妙。本題最大的精華不是怎麼找路徑而是引入方向邊,有興趣的可有看看奆佬的博客的解釋。本題可用鄰接表存圖也可以用鄰接矩陣存圖,不過對於其他題鄰接表的做法更爲保險,所以我一個用的鄰接矩陣其他兩個用的鄰接表。

題解:

一,EK(Edmond—Karp)算法,最原始的方法

        我的理解是一直用bfs找增廣路並記錄它的路線,找到一條後跟新答案,並將這可行弧的正向邊減去可行流,反向加上可行流,直到無法找到下增廣路爲止。
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue> 
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const double e=exp(1.0);
const double pi=acos(-1);
ll mp[205][205],n,m;
ll EK()
{
	ll max_flow=0,flow[205]={0};
	flow[1]=inf;
	while(1)
	{
		int dir[205]={0};
		dir[1]=0;
		queue<int>q;
		q.push(1);
		while(!q.empty())
		{
			int now=q.front();
			q.pop();
			if(now==m)break;
			for(int i=1;i<=m;i++)
			{
				if(i!=1&&mp[now][i]>0&&!dir[i]){
					dir[i]=now;
					flow[i]=min(mp[now][i],flow[now]);
					q.push(i);
				}
			}
		}				
		if(dir[m]==0)break;
		int now=m;
		while(now!=1)
		{
			int next=dir[now];
			mp[now][next]+=flow[m];
			mp[next][now]-=flow[m];
			now=next;
		}
		max_flow+=(ll)flow[m];
	}
	return max_flow;
}
int main()
{
	int s,e,c;
	while(scanf("%lld%lld",&n,&m)!=EOF)
	{
		for(int i=1;i<=m;i++)
		for(int j=1;j<=m;j++)
		mp[i][j]=0;		
		for(int i=0;i<n;i++)
		{
			scanf("%d%d%d",&s,&e,&c);
			mp[s][e]+=(ll)c;
		}
		printf("%lld\n",Ek());
	}
	return 0;
}

二,FF(Ford-Fulkerson)算法,三種方法中最好理解的一種
    和EK算法不一樣,FF算法用的是dfs找增廣路,和EK比起來,最大的優勢是不需要專門用一個數組來記錄可行弧的路線,到匯點時,直接帶着可行弧的流量回去就可以了,其他的和EK差不多了。
#include<stdio.h>
#include<cmath>
#include<string.h>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue> 
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const double e=exp(1.0);
const double pi=acos(-1);
struct Edge{
	int to,cap,rev;//分別記錄可以達到的點 最大流量 反向邊(爲後面的反向標記做準備) 
};
int n,m;
bool use[205];
vector<Edge>v[205];
int dfs(int s,int e,int flow)
{
	if(s==e)return flow;
	use[s]=1;
	for(int i=0;i<v[s].size();i++)
	{
		if(!use[v[s][i].to]&&v[s][i].cap>0)
		{
			Edge now=v[s][i];
			int d=dfs(now.to,m,min(flow,now.cap));
			if(d>0){
				v[s][i].cap-=d;
				v[now.to][now.rev].cap+=d;// 記錄反向邊  有點巧妙  
				return d;
			}
		}
	}
	return 0; 
}
ll FF()
{
	ll max_flow=0;
	while(1)
	{
		memset(use,0,sizeof use);
		int f=dfs(1,m,inf);
		if(f==0)break;
		max_flow+=(ll)f;
	}
	return max_flow;
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		int s,e,c;
		for(int i=1;i<=m;i++)v[i].clear();
		for(int i=0;i<n;i++)
		{
			scanf("%d%d%d",&s,&e,&c);
			v[s].push_back((Edge){e,c,v[e].size()});
			v[e].push_back((Edge){s,0,v[s].size()-1});//最後那個爲標記反向 相當於用vector元素個數來標記 
		}
		printf("%lld\n",FF()); 
	}
	return 0;
}

三,Dinic算法,兩種方法的結合優化
      Dinic是把EK算法和FF算法rua到一起的算法,對於一些橫邊很多的圖運行速度有大大的提升,其他的道理都差不多,直接看代碼
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue> 
#define ll long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const double e=exp(1.0);
const double pi=acos(-1);
int n,m,ans;
struct Edge{
	int to,cap,rev;
};
vector<Edge>v[205];
int dep[205],iter[105];
bool bfs()
{
	queue<int>q;
	q.push(1);
	memset(dep,0,sizeof dep);
	dep[1]=1;//起初沒注意要歸起點要歸1  一直死循環 找了好久的bug 
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		for(int i=0;i<v[now].size();i++)
		{
			if(v[now][i].cap>0&&dep[v[now][i].to]==0)
			{
				dep[v[now][i].to]=dep[now]+1;			
				q.push(v[now][i].to);
			}
		}
	}
	return dep[m]>0;
}
int dfs(int s,int e,int flow)
{
	if(s==e)return flow;
	int ff=0;
	for(int i=0;i<v[s].size();i++)
	{
		if(v[s][i].cap>0&&dep[s]==dep[v[s][i].to]-1)
		{
			int f=dfs(v[s][i].to,e,min(flow-ff,v[s][i].cap));
			if(f>0){
			v[s][i].cap-=f;
			v[v[s][i].to][v[s][i].rev].cap+=f;
			ff+=f;
			//return f;
			}
		}
	}
	if(ff==0)dep[s]=0;
	return ff;
}
ll Dinic()
{
	ll max_flow=0;
	int flow;
	while(bfs())
	{
		//memset(iter,0,sizeof iter);
		while(flow=dfs(1,m,inf))				
			max_flow+=(ll)flow;		
	}
	return max_flow;
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)	
	{
		int s,e,c;
		for(int i=1;i<=m;i++)v[i].clear();		
		
		for(int i=0;i<n;i++)
		{
			scanf("%d%d%d",&s,&e,&c);
			v[s].push_back((Edge){e,c,v[e].size()});
			v[e].push_back((Edge){s,0,v[s].size()-1});
		}
		//ans=0;
		printf("%lld\n",Dinic());
	//	printf("%d\n",ans);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章