【并查集】hdu 1213 How Many Tables

题目描述:

http://acm.hdu.edu.cn/showproblem.php?pid=1213

 

中文大意:

朋友聚会,要求将直接或间接认识的人安排在一个桌子上,问最少需要几张桌子。

 

思路:

一个桌子就是一个集合。若 x y 为朋友关系,则将二者所在的集合合并。

数组 pre[] 记录的是节点的所属集,根节点的所属集 pre[x] = x;

 

代码:

#include<bits/stdc++.h>
using namespace std;

int n,m;
int pre[1001];//各节点的所属集
int height[1001];//各集合的树高,用来做优化 
 
//初始化,每个节点属于独立的集合 
void init(){
    for(int i=1;i<=n;i++){
        pre[i] = i;
        height[i] = 1;
    }
}

//查询节点 x 的所属集
int find(int x){
    //寻找根节点 
    int root = x;
    while(root != pre[root]){
        root = pre[root];
    } 
    
    //路径压缩:将路径上节点的所属集改为根节点 
    int i = x;
    while(pre[i] != root){
        int j = pre[i];
        pre[i] = root;
        i = j;
    }
    return root;
}

//合并(优化后) 
void union_set(int x, int y){
    //查询节点 x 的所属集
    x = find(x);
    //查询节点 y 的所属集
    y = find(y);
    
    //若两个集合的树高相同,则将 x 的所属集并到 y 的所属集 
    if(height[x] == height[y]){
        height[y]++;
        pre[x] = y;
    }//否则,矮树并到高树上,并且高树的树高保持不变 
    else if(height[x] > height[y]){
        pre[y] = x;
    }
    else{
        pre[y] = x;
    }
}

int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%d %d", &n, &m);
        init();
        
        int x,y;
        for(int i=0;i<m;i++){
            scanf("%d %d", &x, &y);
            union_set(x, y);
        }
        
        //统计集合数量 
        int num = 0;
        for(int i=1;i<=n;i++){
            if(pre[i] == i){
                num++;
            }
        }
        printf("%d
", num);
    }
}
作者:老干妈就泡面
本文版权归作者和博客园共有,欢迎转载,但请给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/bjxqmy/p/14479551.html