最大流 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;
}

猜你喜欢

转载自blog.csdn.net/SongBai1997/article/details/84721325