【bzoj1143】[CTSC2008]祭祀river Floyd+网络流最小割

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36616023/article/details/81304732

在遥远的东方,有一个神秘的民族,自称Y族。他们世代居住在水面上,奉龙王为神。每逢重大庆典, Y族都
会在水面上举办盛大的祭祀活动。我们可以把Y族居住地水系看成一个由岔口和河道组成的网络。每条河道连接着
两个岔口,并且水在河道内按照一个固定的方向流动。显然,水系中不会有环流(下图描述一个环流的例子)。

由于人数众多的原因,Y族的祭祀活动会在多个岔口上同时举行。出于对龙王的尊重,这些祭祀地点的选择必
须非常慎重。准确地说,Y族人认为,如果水流可以从一个祭祀点流到另外一个祭祀点,那么祭祀就会失去它神圣
的意义。族长希望在保持祭祀神圣性的基础上,选择尽可能多的祭祀的地点。
Input
第一行包含两个用空格隔开的整数N、M,分别表示岔口和河道的数目,岔口从1到N编号。
接下来M行,每行包含两个用空格隔开的整数u、v,
描述一条连接岔口u和岔口v的河道,水流方向为自u向v。
N≤100M≤1000
Output
第一行包含一个整数K,表示最多能选取的祭祀点的个数。

Sample Input
4 4

1 2

3 4

3 2

4 2
Sample Output
2

【样例说明】

在样例给出的水系中,不存在一种方法能够选择三个或者三个以上的祭祀点。包含两个祭祀点的测试点的方案有两种:

选择岔口1与岔口3(如样例输出第二行),选择岔口1与岔口4。

水流可以从任意岔口流至岔口2。如果在岔口2建立祭祀点,那么任意其他岔口都不能建立祭祀点

但是在最优的一种祭祀点的选取方案中我们可以建立两个祭祀点,所以岔口2不能建立祭祀点。对于其他岔口

至少存在一个最优方案选择该岔口为祭祀点,所以输出为1011。

其实这题是一个二分图的最大独立集问题

我们只要i,j不可以相互到达建立一个inf的边
原点到所有的i建立一条1的边
所有的j向t汇点建立一条1的边

跑一下最大流即可

#include<bits/stdc++.h>
using namespace std;
const int maxn=120000;
struct node
{
	int v,nxt;
	int w;
}edge[maxn*4];
queue<int>q;
int mapp[1000][1000];
int s,t;
int cnt=0,head[maxn];
const int inf=0x3f3f3f3f;
void add_Edge(int u,int v,int w)
{
	edge[cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].nxt=head[u];
	head[u]=cnt++;
}
int dis[maxn];
int bfs()
{
	int x;
	while(!q.empty())
		q.pop();
	memset(dis,0,sizeof(dis));
	dis[s]=1;
	q.push(s);
	while(!q.empty())
	{
		x=q.front();
		q.pop();
		for(int i=head[x];i!=-1;i=edge[i].nxt)
		{
			if(edge[i].w&&!dis[edge[i].v])
			{
				dis[edge[i].v]=dis[x]+1;
				if(edge[i].v==t)
					return 1;
				q.push(edge[i].v);
			}
		}
	}
	return 0;
}
int dfs(int x,int low)
{
	if(x==t)
		return low;
	int temp=low;
	int k;
	for(int i=head[x];i!=-1;i=edge[i].nxt)
	{
		if(edge[i].w&&dis[edge[i].v]==dis[x]+1)
		{
			k=dfs(edge[i].v,min(temp,edge[i].w));
			if(!k)
				dis[edge[i].v]=0;
			edge[i].w-=k;
			edge[i^1].w+=k;
			if(!(temp-=k))
				break;
		}
	}
	return low-temp;
}
int main ()
{
	int n,m;
	cnt=0;
	memset(head,-1,sizeof(head));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int xx,yy;
		scanf("%d%d",&xx,&yy);
		mapp[xx][yy]=1;
	}
		for(int k=1;k<=n;k++)
		{
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=n;j++)
				{
					mapp[i][j]|=(mapp[i][k]&mapp[k][j]);
				}
			}
		}
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				if(mapp[i][j])
				{
					add_Edge(i,j+n,inf),add_Edge(j+n,i,0);
				}
			}
		}
		s=2*n+1;
		t=2*n+2;
		for(int i=1;i<=n;i++)
		{
			add_Edge(s,i,1);
			add_Edge(i,s,0);
		}
		for(int i=n+1;i<=2*n;i++)
			add_Edge(i,t,1),add_Edge(t,i,0); 
		int flow=0;
		while(bfs())
		{
			flow+= dfs(s,inf);
		}
		printf("%d\n",n-flow);
}

/*
1 9
1 6
2 9
3 9
3 8
3 6
4 9
4 6

*/

猜你喜欢

转载自blog.csdn.net/qq_36616023/article/details/81304732