POJ1611The Suspects并查集

来源:互联网 发布:谷嫂淘宝同款排除王 编辑:程序博客网 时间:2024/04/25 04:19

并查集是一种用来管理元素分组情况的数据结构。并查集可以高效地进行如下操作。不过需要注意并查集虽然可以进行合并操作,但是却无法进行分割操作

·查询元素a和元素b是否属于同一组。

·合并元素a和元素b所在的组。

并查集的精髓(即它的三种操作,结合实现代码模板进行理解):

1、Make_Set(x) 把每一个元素初始化为一个集合

初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。

2、Find_Set(x) 查找一个元素所在的集合

查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。
判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。
合并两个集合,也是使一个集合的祖先成为另一个集合的祖先,具体见示意图

3、Union(x,y) 合并x,y所在的两个集合

合并两个不相交集合操作很简单:利用Find_Set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。

题目大意:SARS(非典型肺炎)传播得非常厉害,其中最有效的办法是隔离那些患病、和患病者接触的人。现在有几个学习小组,每小组有几个学生,一个学生可能会参加多个小组。小组中只要有一个人得病,其余的都是嫌疑人。现在已知这些小组的人员,且0号学生已经患病,求一共有多少个嫌疑人。

分析:每个小组的人员属于同一个集合。在根节点记录每个集合的个数num[i],然后找到0所属的根节点,num[findSet(0)]即为所有的嫌疑人数。

*#include <iostream>using namespace std;const int INF=1000000;const int MAX_N=33333;int par[MAX_N];  //父亲int num[MAX_N];  //树的秩记录每个集合的节点个数int rank[MAX_N]; //树的高度//初始化n个元素void init(int n){    for (int i=0; i < n ; i++){        par[i] = i; //使用本身做根        num[i] = 1;        rank[i] = 0;     }}//查询树的根int findroot(int x){if(par[x] != x){        return par[x] = findroot(par[x]);    }    return par[x];}//合并x和y所属的集合void unite(int x,int y){    x=findroot(x);    y=findroot(y);    if(x == y)  return;if(rank[x] < rank[y]){        par[x] = y;        num[y] += num[x];} else{        par[y] = x;        num[x] += num[y];        if(rank[x] == rank[y]) rank[x]++;    }}//判断x和y是否属于同一个集合bool same(int x,int y){    return findroot(x) == findroot(y);}int n,m;int main(){    while(cin>>n>>m&&n)    {        int k,res,vis;        init(n);        while(m--)        {             cin>>k>>vis;            for(int i=1;i<k;i++)            {                cin>>res;                unite(vis,res);            }        }        cout<<num[findroot(0)]<<endl;    }}


0 0
原创粉丝点击