【解题报告】 POJ 1611 The Suspects 并查集基础 (一点自己的感悟)

来源:互联网 发布:盛科网络上市没 编辑:程序博客网 时间:2024/05/18 04:13
题目连接:POJ 1611
最最基础的并查集题目,我就不说什么了。
// POJ1611 The Suspects 并查集//初始化 所有点的父节点初始为-1//查找(找到两点的祖先),合并(合并两个点的祖先)//由于我们事先开了数组记录了祖先的所有所有结点数(办法是进来一个新的结点,则num[祖先]+=num[新节点])////还有我感觉并查集有点类似于 皇帝->大臣->县令->师爷 的关系//一开始大家都是皇帝(这里指初始化),谁都没有融合谁,然后当两个皇帝(这里指不同集合需要合并)在一个国家(这里指同一个集合)的时候,//自然只能留一个皇帝,所以新皇帝就是这个国家的头(这里指头结点),另一个就是这个新皇帝的手下(这里指头结点的集合元素要增加)//当让包括他的手下也一块成为了新皇帝的手下。//现在的情况是,有很多的集合,他们互相存在交集,一旦存在交集我们就视为合并,//那我们的工作就是,合并集合,找到符合我们要求的集合即可。//所以这道题就是找到含有0元素的集合即可///*  test data100 42 1 25 10 13 11 12 142 0 12 99 2200 21 55 1 2 3 4 51 00 0*/#include <cstdio>#include <iostream>#include <cstring>using namespace std;const int MAXSTU = 30010;int father[MAXSTU],num[MAXSTU];void init(int n){ //人数memset(father,-1,sizeof(father));for(int i = 0 ; i < n; i++)num[i] = 1;}int find(int a){if (father[a] == -1) // 本身就是父节点return a;int temp = a;while(father[a] != -1) // 找到该节点的父节点a = father[a];father[temp] = a; // 改变路径(要不要无所谓)return a;}void combination(int a,int b){ // a,b一定是在同一组的a = find(a);//找到他们所在的集合b = find(b);  // 找到他们的头结点,然后合并头结点if (a==b) return; // a b 在同一个集合中,不需要合并// 把 b结点 连接到 a结点 上father[b] = a;num[a] += num[b]; // a集合内的元素个数增加}int main(){freopen("in.txt","r",stdin);int num_stu,num_group;while( scanf("%d%d",&num_stu, &num_group), num_stu || num_group){init(num_stu);if (num_stu == 1){cout << "1" << endl;continue;}for (int j = 0 ; j < num_group; j++){int n,a,b;scanf("%d",&n);scanf("%d",&a);// 默认为输入的第一个数为头结点,即集合标志for (int i = 1; i < n ; i++){scanf("%d",&b);combination(a,b);}}printf("%d\n",num[find(0)]);}return 0;}