poj 3204 Ikki's Story I - Road Reconstruction (最大流的应用)

题目:对于一个有向图,提高一条边的容量,可能可以增加该图的最大流。对给定的图,问存在多少条这样的边。

解法:先求最大流,把边填充好,得到残余图。在残余图中,从s出发DFS,把所有能到达的点标记。同样从t出发DFS,把所有能到达的点标记,不过要注意这里边是反向的。最后枚举边,如果边存在、边是满流并且边的两端分别标记了s和t,那么这条边满足要求。


#include <iostream>
using namespace std;
const int maxN=505;
const int maxC=105;
int map[maxN][maxN],flow[maxN][maxN],pre[maxN],minFlow[maxN],belong[maxN];
int MaxFlow(int N,int s, int t)
{
	int maxFlow=0;
	memset(flow,0,sizeof(flow));
	int myQueue[maxN];
	while(1)
	{
		int l=0,r=0;
		myQueue[r++]=s;
		memset(pre,-1,sizeof(pre));
		pre[s]=-2;
		minFlow[s]=maxC;
		while(l<r)
		{
			int now=myQueue[l++];
			for(int i=0;i<N;i++)
			{
				if(flow[now][i]<map[now][i]&&pre[i]==-1)
				{
					myQueue[r++]=i;
					minFlow[i]=min(minFlow[now],map[now][i]-flow[now][i]);
					pre[i]=now;
				}
			}
			if(pre[t]!=-1)
			{
				int end=t;
				while(pre[end]!=-2)
				{
					flow[pre[end]][end]+=minFlow[t];
					flow[end][pre[end]]=-flow[pre[end]][end];
					end=pre[end];
				}
				maxFlow+=minFlow[t];
				break;
			}
		}
		if(pre[t]==-1) 
			return maxFlow;
	}
}
void NodesConnectedToS(int N,int s,int record[maxN])
{
	record[s]=s;
	bool visited[maxN];
	memset(visited,0,sizeof(visited));
	int myStack[maxN],index=0;
	myStack[index++]=s;
	visited[s]=true;
	while(index--!=0)
	{
		int now=myStack[index];
		for(int i=0;i<N;i++)
		{
			if(map[now][i]>0&&flow[now][i]<map[now][i]&&!visited[i])
			{
				record[i]=s;
				myStack[index++]=i;
				visited[i]=true;
			}
		}
	}
}
void NodesConnectedToT(int N,int t,int record[maxN])
{
	record[t]=t;
	bool visited[maxN];
	memset(visited,0,sizeof(visited));
	int myStack[maxN],index=0;
	myStack[index++]=t;
	visited[t]=true;
	while(index--!=0)
	{
		int now=myStack[index];
		for(int i=0;i<N;i++)
		{
			if(map[i][now]>0&&flow[i][now]<map[i][now]&&!visited[i])
			{
				record[i]=t;
				myStack[index++]=i;
				visited[i]=true;
			}
		}
	}
}
int main()
{
	//freopen("f:\\in.txt","r",stdin);
	memset(map,0,sizeof(map));
	int n,m;
	scanf("%d%d",&n,&m);
	int a,b,c;
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%d",&a,&b,&c);
		map[a][b]=c;
	}
	MaxFlow(n,0,n-1);
	int ans=0;
	memset(belong,-1,sizeof(belong));
	NodesConnectedToS(n,0,belong);
	NodesConnectedToT(n,n-1,belong);
	for(int i=0;i<n;i++)
	{
		if(belong[i]==-1) continue;
		for(int j=0;j<n;j++)
		{
			if(belong[j]==-1) continue;
			if(map[i][j]>0&&map[i][j]==flow[i][j]&&belong[i]!=belong[j])	ans++;
		}
	}
	printf("%d\n",ans);
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值