并查集--PAT.A1107.Social Clusters

来源:互联网 发布:最全的外文数据库 编辑:程序博客网 时间:2024/05/17 06:58

【2017/2/26】
【还有三个测试点不过!!!】【后附正确解法】

/******************3stone*****************************FileName: PAT.A1107.social clusterAuthor:3stoneTime:2017/3/7题意:N个人,每人有不同的爱好,统计有同类爱好的人,并输出人数人数[1,1000]  爱好类型[1,1000] 两个人有一个爱好相同则抽象为一条边用course[h]记录任意一个喜欢h活动的 人的编号作为根节点 findRoot(course[h])找到根节点对当前的人,对他的每一个爱好i,都要合并i 与 findRoot(course[h])还是以学生的编号进行并查集搜索*****************3stone*****************************/#include<cstdio>#include<algorithm>#define maxSize 10010using namespace std;int course[maxSize]; //喜欢 i 课程的任意一学生编号-作为根节点 int tree[maxSize]; //根节点int cluster[maxSize] = { 0 }; //每个群中的人数bool cmp(int a, int b) {    return a > b;}int findRoot(int x) {//寻根    if (-1 == tree[x]) return x;    else {        int temp = findRoot(tree[x]);        tree[x] = temp;//状态压缩         return temp;    }}int main() {    int n;//人数    while (scanf("%d", &n) != EOF) {        for (int i = 1; i <= maxSize; i++) {//初始化            tree[i] = -1;            course[i] = -1;            cluster[i] = 0;        }        for (int i = 1; i <= n; i++) {//输入[注:是n-1行]            int myNum, hNum;            scanf("%d:", &myNum);            for (int j = 1; j <= myNum; j++) {                scanf("%d", &hNum);                if (-1 == course[hNum]) {//此爱好 第一次出现                    course[hNum] = i;  //记录用户的编号                }                else {                    int myRoot = findRoot(course[hNum]);//此爱好 对应的 根用户编号                    if (tree[i] != myRoot) {                        tree[i] = myRoot; //合并集合                     }                }                            //printf("hNum: %d\n", hNum);            }//for-j         }//for-i/*    //  为什么不能给tree[]排序,是要一加sort()就弹错        sort(tree + 1, tree + n + 2, cmp);        printf("tree: %d", tree[1]);        for (int i = 2; i <= n; i++)            printf(" %d", tree[i]);        printf("\ntree over\n");*/        int sum = 0;        for (int i = 1; i <= n; i++) {            if (tree[i] == -1) {                sum++;  //群的个数                cluster[i] = 1;            }            else {                cluster[findRoot(tree[i])]++;            }        }        sort(cluster + 1, cluster + n + 1, cmp);//小心序号        printf("%d\n", sum);        printf("%d", cluster[1]);        for (int i = 2; i <= sum; i++)            printf(" %d", cluster[i]);        printf("\n");    }//while    return 0;}

【以下正确解法 转自《算法笔记》并查集】

#include<cstdio>#include<cmath>#include<algorithm>#define maxSize 1010using namespace std;int father[maxSize];int course[maxSize] = {0};int isRoot[maxSize] = {0}; //记录每个集合的元素个数 void init(int n){//初始化     for(int i = 1; i <= n; i ++){        father[i] = -1;        isRoot[i] = false;    }}int findF(int x){//寻找根节点     if(-1 == father[x])        return x;    else{        int temp = findF(father[x]);        father[x] = temp;//状态压缩         return temp;    } }void Union(int a, int b){//合并集合     int ta = findF(a);    int tb = findF(b);    if(ta != tb)        father[ta] = tb;}bool cmp(int a, int b){    return a > b;}int main(){    int n, k, h;    while(scanf("%d", &n) != EOF){        init(n);        for(int i = 1; i <= n; i++){            scanf("%d:", &k);            for(int j = 1; j <= k; j++){                scanf("%d", &h);                if(0 == course[h]){                    course[h] = i;                }                Union(i, findF(course[h]));//爱好相同,合并集合             }        }         for(int i = 1; i <= n; i++){//统计人数             isRoot[findF(i)]++;        }         int ans = 0;        for(int i = 1; i <= n; i++){            if(isRoot[i] != 0)                ans++;        }        printf("%d\n", ans);        sort(isRoot+1, isRoot + n + 1, cmp);//不能在[1-ans]排,不能保证根全         for(int i = 1; i < ans;i++)            printf("%d ", isRoot[i]);        printf("%d\n", isRoot[ans]);    }//while    return 0;}
0 0
原创粉丝点击