• pku1611


    嘿嘿,第一道并查集的题目,一个基本的应用,求一个集合的元素个数,不过中间同样涉及了俩个基本的操作,查找还有合并

    题目大意:有n个学生(标号为0 to n-1),m个学生社团,给出每个社团里所有学生的标号,并假设0号学生患有SARS(社团里只要用一个学生患病,则整个社团里的学生都会被隔离),问最后一共会有多少学生被隔离?
    这是一个最基础的并查集的应用,扫描每一个社团,只要两个学生出现在同一个社团,则将这两个集合合并起来,最后输出0号点所在集合的rank值集合(rank值记录这个集合中的元素个数并用一个flag值跟踪0号元素所在集合标号)即可。

    #include<stdio.h>
    #define MAXN 30010
    int f[MAXN],r[MAXN],flag;
    //f[x]表示元素f的父节点
    ////由于不知道应该将子树挂到那个集合上面去,故需要一个准则,这里的准则是将子树挂到
    ////r值大的集合上面去,初始状态下r数组的值均为一,代表每个分支下只有一个数字
    //flag用来追踪0号学生所属集合
    int find(int x)
    {
    	if(x==f[x])
    		return f[x];
    	f[x]=find(f[x]);
    	return f[x];
    }//路径压缩
    void Union(int x,int y)
    {
    	int a=find(x);
    	int b=find(y);
    	if(a==b) return ;
    	if(r[a]<=r[b])
    	{
    		f[a]=b;
    		r[b]+=r[a];
    		if(a==flag)
    			flag=b;//扩大0号学生的感染范围,b为0号学生所属集合的父节点
    	}
    	else {
    		f[b]=a;
    		r[a]+=r[b];
    		if(b==flag)
    			flag=a;
    	}
    	return ;
    }
    int main()
    {
    	int i,j,n,m,temp1,temp2,num;
    	while(scanf("%d %d",&n,&m)!=EOF &&(n||m))
    	{
    		flag=0;
    		for(i=0;i<n;i++)//有0号学生,所以这里i必须从0开始
    		{
    			f[i]=i;
    			r[i]=1;
    		}
    		for(i=1;i<=m;i++)
    		{
    			scanf("%d",&num);
    			for(j=1;j<=num;j++)
    			{
    				if(j==1)
    				{
    					scanf("%d",&temp1);
    				}
    				else {
    					scanf("%d",&temp2);
    					Union(temp1,temp2);
    				}
    			}
    		}
    		printf("%d\n",r[flag]);//输出集合中的元素个数
    	}
    	return 0;
    }
    
  • 相关阅读:
    chrome视频播放加速
    centos磁盘空间重新分配
    mseed2sac的安装和使用
    查找台站信息得到台站数据的网站
    java install
    CMT learning
    hosts持续更新
    what is SVD and how to calculate it
    google 镜像
    z变换
  • 原文地址:https://www.cnblogs.com/nanke/p/2035104.html
Copyright © 2020-2023  润新知