• 1107. Social Clusters (30)


    距离PAT考试还有17天,最重要的是做透每一题

    (1)

    思路:

    基本就是利用并查集

    以人的标号为集合元素然后通过爱好来合并各个集合

    这里有个技巧是用一个数组hobby来做映射,hobby数组全部初始为0,然后一旦有一个人有这个hobby就将这个人的标号存进去

    下次一旦再有人是这个hobby就和hobby中存的那个人的集合合并从而达到相应的效果

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <algorithm>
    using namespace std;
    
    #define M 1010
    int p[M];
    int hobby[M];
    int num[M];
    int cnt;
    
    bool cmp(int a,int b) {return a>b;}
    void makeset(int x) {
      p[x]=x;
      num[x]=1;
    }
    
    int findset(int x) {
      int px=x,i;
      while(px != p[px]) px=p[px]; // find root
      while(x != px) { //path compression
        i=p[x];
        p[x]=px;
        x=i;
      }
      return px;
    }
    
    void unionset(int x,int y) {
      x=findset(x);
      y=findset(y);
      p[x]=y;
      cnt--;
    }
    
    int main() {
      int n;
      scanf("%d",&n);
      cnt=n;
      memset(hobby,0,sizeof(hobby));
      memset(p,0,sizeof(p));
      memset(num,0,sizeof(num));
      for(int i=1;i<=n;i++) {
        int k;
        scanf("%d:",&k);
        makeset(i);
        for(int j=0;j<k;j++) {
          int h;
          scanf("%d",&h);
          if(hobby[h] != 0) unionset(hobby[h],i);
          hobby[h]=i;
        }
      }
      printf("%d
    ",cnt);
    
      for(int i=1;i<=n;i++){
        num[findset(i)]++;
      }
      sort(num,num+M,cmp);
    //这里这样做是因为根节点的值一定是最大的其他节点最多也就是1
    //排序后,大的cnt个节点一定在前面    
      for(int i=0;i<cnt;i++) {//减一是因为父节点自己也会把自己再算一次
        i==0? printf("%d",num[i]-1):printf(" %d",num[i]-1);
      }
      return 0;
    }

    这里研究一下并查集

    它维护一些不想交的集合,它是集合的集合

    接口是

    void makeset(int i);

    int findset(int x);

    void unionset(int x,int y);

    具体如下:

    void makeset(int x) {
      p[x]=x;
      rank[x]=0;
    }

    这里rank是为了记录深度以提高效率而做的

    int findset(int x) {
      int px=x;
      while(px!=p[px]) px=p[px];//find root
      while(x!=px) { //root compression
        i=p[x];
        p[x]=px;
        x=i;
      }
      return px;
    }

    为了效率进行路径压缩

    void unionset(int x,int y) {
      x=findset(x);
      y=findset(y);
      if(rank[x] > rank[y]) {
        p[x]=y;
      }else {
        p[y]=x;
        if(rank[x]==rank[y]) rank[x]++;
      }
    }

    将较浅的合并到较深的以提高效率

  • 相关阅读:
    边框渐变
    循环遍历对象的方法
    H5 判断手机设备类型及不同类型调起分享
    Java工具延时队列
    银行风控模型
    解除网页复制需登陆限制 鸟
    weditor安装出错一直装不上
    【刷题】【dp】蓝桥·回路计数
    【笔记】第六章 利用数组处理批量数据
    【笔记】【C语言】格式控制符 / 格式输出函数printf()详解
  • 原文地址:https://www.cnblogs.com/tclan126/p/8488125.html
Copyright © 2020-2023  润新知