1. 程式人生 > >最大流 Dinic演算法

最大流 Dinic演算法

Dinic演算法模板

 

鄰接矩陣形式

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
 
using namespace std;
 
const int N=205;
const int INF=0x3f3f3f3f;
 
int g[N][N],layer[N];
bool vis[N];
int n,m;//1是源點 n是匯點
 
 
bool CounterLayer()
{
	queue<int>q;
	memset(layer,-1,sizeof(layer));
	layer[1]=0;
	q.push(1);
	while(!q.empty())
	{
		int v=q.front();
		q.pop();
		for(int i=1;i<=n;i++)
		  if(g[v][i]>0&&layer[i]==-1)
		  {
		  	 layer[i]=layer[v]+1;
		  	 if(i==n)//分層到匯點即可 
		  	   return true;
		  	 else
		  	   q.push(i);
		  }
	}
	return false;
} 
 
int Dinic()
{
	int ans=0;
	vector<int>q; 
	while(CounterLayer())//只要能分層 
	{
		q.push_back(1);//源點入棧
		while(!q.empty())
		{
			int u=q.back();
			if(u==n)//如果u是匯點,在路徑中找容量最小邊 
			{
				int temp=INF;
				int st;//容量最小邊的起點
				for(int i=1;i<q.size();i++)
				{
					int vs=q[i-1];
					int ve=q[i];
					if(g[vs][ve]>0&&temp>g[vs][ve])
					  temp=g[st=vs][ve];
				}
				//改圖
				ans+=temp;
				for(int i=1;i<q.size();i++)
				{
					int vs=q[i-1];
					int ve=q[i];
					g[vs][ve]-=temp;
					g[ve][vs]+=temp;
				}
				//退棧到 st 成為棧頂,以便繼續dfs
				while(!q.empty()&&q.back()!=st)
					q.pop_back();
			}
			
			else//如果u不是匯點 
			{
				int i;
				for(i=1;i<=n;i++)//往下一層結點走
				  if(g[u][i]>0&&layer[i]==layer[u]+1)
				  {
					  q.push_back(i);
					  break;	
				  }
				if(i>n)//找不到下一個結點
				{
					layer[q.back()]=-1;
					q.pop_back(); 
				}
			}
		 } 
	}
	return ans;
}
 
int main()
{
	while(~scanf("%d%d",&m,&n))
	{
		int s,e,c;
		memset(g,0,sizeof(g));
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&s,&e,&c);
			g[s][e]+=c;
		}
		printf("%d\n",Dinic());
	}
	return 0;
}

鄰接表形式(前向星實現)

#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
 
using namespace std;
 
const int N=205;
const int INF=0x3f3f3f3f;
 
int layer[N];
bool vis[N];
int n,m;//1是源點 n是匯點
 
//前向星實現鄰接表
int M;
int head[N];
 
struct Edge{
	int from,to,next,w;
}edge[N*N];
 
void add(int from,int to,int w)
{
	edge[M].next=head[from];
	edge[M].to=to;
	edge[M].w=w;
	head[from]=M++;
} 
 
bool CountLayer()//分層 
{
	queue<int>q;
	memset(layer,-1,sizeof(layer));
	layer[1]=0;
	q.push(1);
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		for(int k=head[u];k!=-1;k=edge[k].next)
		{
			int v=edge[k].to;
			int w=edge[k].w;
			if(w>0&&layer[v]==-1)
			{
				layer[v]=layer[u]+1;
				if(v==n)
				  return true;
				else
				  q.push(v); 
			}
		} 
	}
	return false;
} 


int Dinic(int s,int t)
{
	int ans=0;
	int q[N*N];
	while(CountLayer())
	{
		int k,u,v,back,size=1;
		while(size)
		{
			u=(size==1)?s:edge[q[size-1]].to;
			//u是匯點 
			if(u==t)
			{
				int temp=INF;
				for(int i=1;i<size;i++)
				{
					k=q[i];
					if(edge[k].w>0&&edge[k].w<temp)
					{
						temp=edge[k].w;
						back=i;
					}
				}
				//改圖
				for(int i=1;i<size;i++)
				{
					k=q[i];
					edge[k].w-=temp;
					edge[k^1].w+=temp;
				}
				ans+=temp;
				size=back; 
			}
			
			//u不是匯點
			else
			{
				for(k=head[u];k!=-1;k=edge[k].next)
				{
					int v=edge[k].to;
					if(edge[k].w>0&&layer[v]==layer[u]+1)
					  break;
				}
				if(k!=-1)
				  q[size++]=k;
				else
				{
					layer[u]=-1;
					size--;
				}
			} 
		}
	}
	return ans;
} 
 
int main()
{
	while(~scanf("%d%d",&m,&n))
	{
		int s,e,c;
		M=0;
		memset(head,-1,sizeof(head));
		for(int i=1;i<=m;i++)
		{
			scanf("%d%d%d",&s,&e,&c);
			add(s,e,c);
			add(e,s,0);//新增反向邊 
		}
		printf("%d\n",Dinic(1,n));
	}
	return 0;
}