网络流

目录

网络流简介

 POJ  1273 Drainage Ditches


另一篇整理的博客

网络流简介

 

 POJ  1273 Drainage Ditches

题意:给定点数,边数,每条 边的容量,以及源点,汇点,求最大流。

#include<iostream>
#include<queue>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn=300;
int G[maxn][maxn];
int Prev[maxn];//存放节点的前驱结点,方便加反向边 
bool Visited[maxn];
int n,m;
/*从结点1开始压入栈中,然后寻找增广路径,并且用Prev来记录结点的前驱结点,找到一条增广路径之后,就开始求最大流
求完最大流之后,再加反向边修改图G。
*/
int Augment()
{
	deque<int>q;
	memset(Prev,0,sizeof(Prev));
	memset(Visited,0,sizeof(Visited));
	Prev[1]=0;
	Visited[1]=1;
	q.push_back(1);
	bool bFindPath=false;
	int v;
	while(!q.empty())
	{
		v=q.front();
	    q.pop_front();
	    for(int i=1;i<=m;i++)
	    {
	    	if(G[v][i]>0 && Visited[i]==0)
	    	{
	    		Prev[i]=v;
	    		Visited[i]=1;
	    		if(i==m)
	    		{
	    			bFindPath=true;
	    			q.clear();
					break;
				}else{
					q.push_back(i);
				}
			}
		}  
	}
	     if(!bFindPath)
	        return 0;
	     int nMinFlow=999999999;
	     v=m;
	     while(Prev[v])
	     {
	     	nMinFlow=min(nMinFlow,G[Prev[v]][v]);
	     	v=Prev[v];
		 }
	     v=m;
	     while(Prev[v])
	     {
	     	G[Prev[v]][v]-=nMinFlow;
			G[v][Prev[v]]+=nMinFlow;//加反向边 
			v=Prev[v]; 
		 }
	return nMinFlow; 
}

int main()
{
   	while(cin>>n>>m)
   	{
   	    int s,e,c;
		memset(G,0,sizeof(G));
		for(int i=0;i<n;i++)
		{
		    cin>>s>>e>>c;
			G[s][e]+=c;	
		}	
		int MaxFlow=0;
		int aug;
		while(aug=Augment())
		{
			MaxFlow+=aug;
		}
		cout<<MaxFlow<<endl;
	}
	return 0;
} 

 增广路径的优化--------->Dinic

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<deque>
#include<string.h>
using namespace std;
#define INF 999999999
const int maxn=300;
int G[maxn][maxn];
bool Visited[maxn];
int Layer[maxn];//分层数组
int n,m; 
bool CountLayer()
{
	  int layer=0;
	  deque<int>q;
	  memset(Layer,0xff,sizeof(Layer));
	  Layer[1]=0;
	  q.push_back(1);
	  while(!q.empty())
	  {
	  	int v=q.front();
	  	q.pop_front();
	  	for(int j=1;j<=m;j++)
	  	{
	  		if(G[v][j]>0 && Layer[j]==-1)
	  		{
	  		   Layer[j]=Layer[v]+1;
			   if(j==m) //如果已经找到了汇点 
			      return true;
			   else
			      q.push_back(j);
			}
		}
	  }
	  return false;
}
int Dinic()
{
	int s;
	int nMaxFlow=0;
	deque<int>q;
	while(CountLayer())
	{
		q.push_back(1);
		memset(Visited,0,sizeof(Visited));
		Visited[1]=1;
		while(!q.empty())
		{
			int nd=q.back();
			if(nd==m)//nd是汇点 
			{
				int nMinC=INF;//最小流量 
				int nMinC_vs;//容量最小的边的起点 
				for(int i=1;i<q.size();i++)
				{
					int vs=q[i-1];
					int ve=q[i];
					if(G[vs][ve]>0)
					{
						if(nMinC>G[vs][ve])
						{
							nMinC=G[vs][ve];
							nMinC_vs=vs;
						}
					}
				}
				nMaxFlow+=nMinC;
				for(int i=1;i<q.size();i++)
				{
					int vs=q[i-1];
					int ve=q[i];
					G[vs][ve]-=nMinC;
					G[ve][vs]+=nMinC;
				}
				
				while(!q.empty() && q.back()!=nMinC_vs)
				{
					Visited[q.back()]=0;
					q.pop_back();
				}
			}else{ //不是汇点 
			   int i;
				for( i=1;i<=m;i++)
				{
					if(G[nd][i] >0 && Layer[i]==Layer[nd]+1 && !Visited[i])
					{//往下一层没有走过的结点走 
						Visited[i]=1;
						q.push_back(i);
						break;
					}
				}
				if(i>m)//找不到下一个节点 
				  q.pop_back();//回溯 
			}
		}
	}
	return nMaxFlow;
}
int main()
{
    while(cin>>n>>m)
	{
		int s,e,c;
		memset(G,0,sizeof(G));
		for(int i=0;i<n;i++)
		{
			cin>>s>>e>>c;
			G[s][e]+=c;
		}
		cout<<Dinic()<<endl;
	}	
	return 0;
}

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值