CSP-Week6 ProblemB 并查集详解和例题(POJ - 1611)

CSP-普适结构–并查集

知识简述

并查集是一种图论中十分常见的数据结构,在联通模块和生成树问题中具有十分重要的作用,因此并查集是在程序设计中必须掌握的知识模块。
正如其名,并查集结构主要关注两个方面:
1、并操作
2、查操作
在这里插入图片描述要组织这种结构,可以使用各种各样的数据结构:数组、链表或者是树都可以做到。但是考虑到在比赛时的实现简易度,使用数组比较方便易行。
在对节点组进行并和查操作时,找出他得所有同组节点是不容易的,且可能会耗费掉巨大的时间复杂度,因此我们换一种思路:将一个元素作为每个组别的代表,在进行并查时只需要使用代表元素进行操作即可。为了减少空间开销,我们可以将整个并查集组织成下图的结构:
在这里插入图片描述每个组别使用祖先父亲节点作为这个点的代表元素,使用一个par[]数组来指示每个点的祖先即可。
考虑3种组织操作操作:
初始化:
在没有进行并之前,每个节点是独立的,其同组节点只有自己,因此可以直接将每个点的祖先置为自己,初始化状态:
在这里插入图片描述
查操作:
在查询一个节点的所属组别是,只需要查询出其祖先父亲节点就可以完成对组别的标识,进而进行后续操作,查操作的示例图:
在这里插入图片描述并操作:在进行并操作时,关键的是如何组织两个结构类型的根节点,这决定了整个并查集的性能(如果并查集的高度过大,同层的元素较少会导致性能退化)
因此我们使用点数优先的路径压缩法:(想了解各种路径压缩优化方法的同学可以百度)
在试行并操作时遵从两个操作原则:
1、将节点数较少的集合并入到节点数较少的集合中。
2、并入时直接将“小集合”祖先节点连接到“大集合”祖先节点的孩子节点即可。
操作图例如下:
在这里插入图片描述具体实现源码(c++):

const int max_floor=3e4;
int parent[max_floor];
int number[max_floor];
int find(int pos)
{
    
    
    if(parent[pos]==pos)
    return pos;
    else 
    return find(parent[pos]); 
}
void unit(int x,int y)
{
    
    
    int father_x=find(x);
    int father_y=find(y);
    if(father_x==father_y)
    return;
    if(number[father_x]>number[father_y])
    swap(father_x,father_y);
    parent[father_x]=father_y;
    number[father_y]+=number[father_x];
    //cout<<x<<"--"<<father_x<<" "<<y<<"--"<<father_y<<endl; 
}

题目概述

新型冠状病毒肺炎(Corona Virus Disease 2019,COVID-19),简称“新冠肺炎”,是指2019新型冠状病毒感染导致的肺炎。
如果一个感染者走入一个群体,那么这个群体需要被隔离!
小A同学被确诊为新冠感染,并且没有戴口罩!!!!!!
需要尽快找到所有和小A同学直接或者间接接触过的同学,将他们隔离,防止更大范围的扩散。
众所周知,学生的交际可能是分小团体的,一位学生可能同时参与多个小团体内。
请你编写程序解决!戴口罩!!

INPUT&输入样例

多组数据,对于每组测试数据:
第一行为两个整数n和m(n = m = 0表示输入结束,不需要处理),n是学生的数量,m是学生群体的数量。0 < n <= 3e4 , 0 <= m <= 5e2
学生编号为0~n-1,小A编号为0
随后,m行,每行有一个整数num即小团体人员数量。随后有num个整数代表这个小团体的学生。
输入样例:

100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0

OUTPUT&输出样例

输出要隔离的人数,每组数据的答案输出占一行
输出样例:

4
1
1

题目重述

题目是一道实事题,但也间接体现出了并查集算法的广泛作用,并查集的灵魂是不变的。题目大意:给定各点之间的连通关系,求解0号节点的同组节点个数。

思路概述

题目比较简单,只需要将题目给定的集合转换为联通边的概念,然后跑一遍即可完成。
题目是一道板子题,但是重要的是领会并查集的精髓:连通分支的合并和搜索祖先。

题目源码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int max_floor=3e4;
int parent[max_floor];
int number[max_floor];
int find(int pos)
{
    
    
    if(parent[pos]==pos)
    return pos;
    else 
    return find(parent[pos]); 
}
void unit(int x,int y)
{
    
    
    int father_x=find(x);
    int father_y=find(y);
    if(father_x==father_y)
    return;
    if(number[father_x]>number[father_y])
    swap(father_x,father_y);
    parent[father_x]=father_y;
    number[father_y]+=number[father_x];
    //cout<<x<<"--"<<father_x<<" "<<y<<"--"<<father_y<<endl; 
}
int main()
{
    
    
    int student,group=0;
    cin>>student>>group;
    while(student!=0)
    {
    
    
    for(int i=0;i<student;i++)
    {
    
    
        parent[i]=i;
		number[i]=1;
    }
    for(int i=0;i<group;i++)
    {
    
    
        int parter=0;
        cin>>parter;
        int start=0;
        cin>>start;
        int point=0;
        for(int j=1;j<parter;j++)
        {
    
    
        	cin>>point;
        	unit(start,point);
		}
    }
    int flag=find(0);
    cout<<number[flag]<<endl;
    cin>>student>>group;
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43942251/article/details/105273590