Junk-Mail Filter HDU-2473 并查集

题目链接:HDU-2473

主要思路:

初始时将所有点有与它的编号+n的点并在一起,合并时照常,删除从一个集合里删除一个点就是给这个点在给一个新的集合。最后统计每个点所在集合的个数即可(编号小于n)。注意要开n*2+m个集合(即fa数组的大小),否则getfa操作会出问题,预处理fa数组也是一样。

AC代码:

#include<cstdio>
#include<cstring>
#define M 100005
char s[10];
int fa[M*12];//n*2+m大于M*10 
bool mark[M*12];
int getfa(int v){
	if(fa[v]==v)return fa[v];
	return fa[v]=getfa(fa[v]);
}
int main(){
	int n,m,Case=0;
	while(~scanf("%d%d",&n,&m)){
		if(!n&&!m)return 0;
		memset(mark,0,sizeof(mark));
		for(int i=0;i<n;i++)fa[i]=i+n;//前面的数的fa都连到后面,这样从集合删除一个数时就不会把这个集合的数都删掉 
		for(int i=n;i<=n*2+m;i++)fa[i]=i;//如果右端点开小会MLE(fa数组为0,getfa是出错) 
		int cnt=n*2;
		while(m--){
			scanf("%s",s);
			if(s[0]=='M'){
				int a,b;
				scanf("%d%d",&a,&b);
				int x=getfa(a),y=getfa(b);
				fa[x]=y;
			}else{
				int d;
				scanf("%d",&d);
				fa[d]=cnt++;//新开一个集合给他 
			}
		}
		int ans=0;
		for(int i=0;i<n;i++){
			int x=getfa(i);
			if(!mark[x]){//判断这个集合有没有出现 
				ans++;
				mark[x]=1;
			}
		}
		printf("Case #%d: %d\n",++Case,ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35320178/article/details/81605876