poj 1273 Drainage Ditches--最大流--sap

/*
sap的非递归实现  0ms  还不错
让人纠结的啊   我写的是吧d[]初始化为0  WA
看别人的模版初始化为m,过了
又看到别人用数组标记,过了(貌似也不对,居然过了)
我写了一个数组标记访问,没过
*/
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int N=300;
const int inf=0x7fffffff;
int  map[N][N];
int n,m,src,sink,minf;
int d[N],numbs[N],curnode[N],pre[N],vis[N];
void revbfs()//初始化距离    
{
/*	int u,v;//我的初始化为0    没过   谁给看看
	memset(d,0,sizeof(d));
	memset(numbs,0,sizeof(numbs));
	d[sink]=0;
	numbs[0]=1;
	queue<int>q;
	q.push(sink);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		for(v=1;v<=m;++v)
		{
			if(map[v][u]==0||d[v]||v==sink)
				continue;
			d[v]=d[u]+1;
			numbs[d[v]]++;
			q.push(v);
		}
	}
	return;*/
	
/*	int i,u; //别人的数组标记访问  过了
	queue<int>q;
	memset(vis,0,sizeof(vis));  
	d[sink]=0;  
	vis[sink]=true;  
	q.push(sink);
	while(!q.empty())  
	{  
		u=q.front();
		q.pop();
		for(i=1; i<=m;++i)  
			if(!vis[i] &&map[u][i])  
			{  
				d[i]=d[u]+1;  
				vis[i]=true;  
				q.push(i);
			}  
	}*/
	
/*	int u,v;//我的素族标记访问  没过
	memset(numbs,0,sizeof(numbs));
	memset(vis,0,sizeof(vis));
	d[sink]=0;
	numbs[0]=1;
	vis[sink]=1;
	queue<int>q;
	q.push(sink);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		for(v=1;v<=m;++v)
		{
			if(!vis[v]&&map[v][u])
			{
				vis[v]=1;
				d[v]=d[u]+1;
				numbs[d[v]]++;
				q.push(v);
			}
		}
	}
	return;*/
	
/*	int u,v;//模板上的  初始化为m   过了
	for(u=1;u<=m;++u)
	d[u]=m;
	memset(numbs,0,sizeof(numbs));
	d[sink]=0;
	numbs[0]=1;
	queue<int>q;
	q.push(sink);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		for(v=1;v<=m;++v)
		{
			if(map[v][u]==0||d[v]<m)
				continue;
			d[v]=d[u]+1;
			numbs[d[v]]++;
			q.push(v);
		}
	}*/
}
int retreat(int &i)//修改d[i]=min(d[j]+1|)     更新相关numbs
{
	int t,mind=m-1,j;//为什么mind=m-1?这就是最大的 
	for(j=1;j<=m;++j)
		if(map[i][j]>0&&d[j]<mind)
			mind=d[j];
	t=d[i];
	d[i]=mind+1;
	numbs[t]--;
	numbs[d[i]]++;
	if(i!=src)
		i=pre[i];//为什么   退回上一层      i中不到允许边了,这个操作试图找到允许边    没有这部分可能会造成死循环
	return numbs[t];
}
int augment()//找到最窄的路  然后按那个增广
{
	int i,j;
	int t=inf;
	for(i=sink,j=pre[i];i!=src;i=j,j=pre[i])
	{
		if(t>map[j][i])
			t=map[j][i];
	}
	for(i=sink,j=pre[i];i!=src;i=j,j=pre[i])
	{
		map[j][i]-=t;
		map[i][j]+=t;
	}
	return t;
}
int sap()
{
	memset(pre,0,sizeof(pre));
	int i,j;
	memset(d,0,sizeof(d));//放在这儿  可省去revbfs();
	revbfs();
	for(i=1;i<=m;++i)
		curnode[i]=1;//递归通过这个实现    curnode[i]表示的是i的后继结点的开始位置,小于它的已经访问过了
	i=src;
	while(d[src]<m)
	{
		for(j=curnode[i];j<=m;++j)
			if(map[i][j]>0&&d[i]==d[j]+1)
				break;
		if(j<=m)
		{
			curnode[i]=j;
			pre[j]=i;
			i=j;
			if(i==sink)
			{
				minf+=augment();
				i=src;//这都回去了 怎么实现递归?     通过cuenode实现    curnode是当前路径上的点  所以可以通过这个恢复递归状态
			}
		}else
		{
			curnode[i]=1;//因为i没有可用的允许边,下面试图通过修改d[i]来寻找新的,若找到,那么新的都还没有搜索过,所以要从1开始
			if(retreat(i)==0)
				break;
		}
	}
	return minf;
}
int main()
{
	int i,a,b,c;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		minf=0;
		src=1;
		sink=m;
		memset(map,0,sizeof(map));
		for(i=1;i<=n;++i)
		{
			scanf("%d%d%d",&a,&b,&c);
			map[a][b]+=c;
		}
		printf("%d\n",sap());
	}
}
/*
	居然用了16ms  用循环写的时候,不用bfs好像也是0ms  这个跟那个好像差不多吧   居然运行了两次都是16ms 
	谁知道为什么啊
*/
#include<stdio.h>
#include<string.h>
int m,n,src,sink;
int d[205],num[205];
int map[205][205];
int min(int a,int b){return a<b?a:b;}
int dfs(int u,int f)
{
	if(u==sink)
		return f;
	int v,mind=n-1,last=f,cost;;
	for(v=1;v<=n;++v)
	{
		if(map[u][v]>0)//有流量
		{
			if(d[u]==d[v]+1)//有允许边
			{
				cost=dfs(v,min(last,map[u][v]));
				map[u][v]-=cost;//修改图
				map[v][u]+=cost;
				last-=cost;//修改剩余流量

				if(d[src]>=n)//结束标志
					return f-last;

				if(last==0)//使用完就退出
					break;
			}
			if(d[v]<mind)//下面更新距离的时候用  求其能连接到的最小距离   这个判断和上边的那个判断并列  因为他们是互斥的,只有当找不到允许边的时候才用得着mind
				mind=d[v];
		}
	}

	if(last==f)//流量没有使用  即  没有允许边
	{
		--num[d[u]];
		if(num[d[u]]==0)//若出现断层
		{
			d[src]=n;
		}
		d[u]=mind+1;
		++num[d[u]];
	}
	return f-last;
}
int sap()
{
	int ret=0;
	memset(d,0,sizeof(d));//距离
	memset(num,0,sizeof(num));//距离数
	num[0]=n;
	while(d[src]<n)
		ret+=dfs(src,0x7fffffff);
	return ret;//最大流
}
int main()
{
	int i,a,b,c;
	while(scanf("%d%d",&m,&n)!=EOF)
	{
		src=1;
		sink=n;
		memset(map,0,sizeof(map));
		for(i=1;i<=m;++i)
		{
			scanf("%d%d%d",&a,&b,&c);
			map[a][b]+=c;
		}
		printf("%d\n",sap());
	}
	return 0;
}


你可能感兴趣的:(poj 1273 Drainage Ditches--最大流--sap)