zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    记录上锁(字节范围锁,特例:锁住文件的某一部分或者整个文件)
    读写锁的实现原理(pthread_rwlock_t)
    Linux 互斥锁的实现原理(pthread_mutex_t)
    System V消息队列
    Web安全之SQL注入攻击技巧与防范
    如何正确地写出单例模式
    java的concurrent用法详解
    java并发编程-Executor框架
    java.util.concurrent包分类结构图
    Java多线程干货系列(1):Java多线程基础
  • 原文地址:https://www.cnblogs.com/nanke/p/2035104.html
Copyright © 2011-2022 走看看