您的位置:首页 > 其它

BZOJ 1854[Scoi2010]游戏

2016-01-23 16:24 337 查看
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1854

[分析]

我们将每个武器看作一条边,分别连接两个权值。

因为对于每个点的数量为n的联通块,当它没有环的时候,最多只有其中的n-1个点能够符合条件;

而对于有环的联通块,其n个点都能够符合条件。

我们设vis[i]表示权值i能否符合条件,则当联通块没有环的时候,只有权值最大的点的vis为false,而其他的点的vis都为true;

当联通块有环的时候,所有的点vis都为true。

如何实现这一点呢?若题目中的两个权值不在同一个集合中时,将代表员小的合并进代表员大的,将代表员小的vis设为false;

若它们在同一个集合中,则其代表员的vis也设为false;

这样就可以保证前面的条件。最后只要for一遍vis数组就可以了。

注意:因为答案可能为10000,所以要for到10001。

具体实现方法见代码:

#include <iostream>
#include <cstdio>

using namespace std;

int n;
int fa[1000010];
bool vis[1000010];

int find(int x){
	int tmp=x,pre;
	while(tmp!=fa[tmp])tmp=fa[tmp];
	while(x!=tmp){
		pre=fa[x];
		fa[x]=tmp;
		x=pre;
	}
	return tmp;
}

void merge(int x,int y){
	int fx=find(x),fy=find(y);
	if(fx>fy){
		int t=fx;
		fx=fy;
		fy=t;
	}
	vis[fx]=true;
	fa[fx]=fy;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=10001;i++)fa[i]=i;
	for(int i=1;i<=n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		if(find(x)==find(y))vis[find(x)]=true;
		else merge(x,y); 
	}
	for(int i=1;i<=10001;i++)if(!vis[i]){printf("%d\n",i-1);break;}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: