zoukankan      html  css  js  c++  java
  • AcWing 837. 连通块中点的数量 并查集

    地址 https://www.acwing.com/problem/content/description/839/

    给定一个包含n个点(编号为1~n)的无向图,初始时图中没有边。
    
    现在要进行m个操作,操作共有三种:
    
    “C a b”,在点a和点b之间连一条边,a和b可能相等;
    “Q1 a b”,询问点a和点b是否在同一个连通块中,a和b可能相等;
    “Q2 a”,询问点a所在连通块中点的数量;
    输入格式
    第一行输入整数n和m。
    
    接下来m行,每行包含一个操作指令,指令为“C a b”,“Q1 a b”或“Q2 a”中的一种。
    
    输出格式
    对于每个询问指令”Q1 a b”,如果a和b在同一个连通块中,则输出“Yes”,否则输出“No”。
    
    对于每个询问指令“Q2 a”,输出一个整数表示点a所在连通块中点的数量
    
    每个结果占一行。
    
    数据范围
    1≤n,m≤105
    输入样例:
    5 5
    C 1 2
    Q1 1 2
    Q2 1
    C 2 5
    Q2 5
    输出样例:
    Yes
    2
    3

    算法1
    (暴力枚举) O(n2)O(n2)
    起始每次遇到并查集的题目,总会下意识的先去想想哈希。
    但是哈希的合并那就逊色多了。不过这次也AC了。
    计算相同集合里的个数要注意了,尽量在合并的时候注意次序,
    序号小的统计记录不重复的记录下之后的所有大序号元素的个数。

    序号大的元素记录里不要统计小序号元素个数,避免重复。

    C++ 代码

    #include <iostream>
    #include <map>
    #include <set>
    using namespace std;
    
    
    /*
    //并查集模板
    void init(int n)
    {
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    int get(int x)
    {
        return fa[x]==x?x:fa[x]=get(fa[x]);//路径压缩,防止链式结构
    }
    void merge(int x,int y)
    {
        fa[get(x)]=get(y);
    }
    
    给定一个包含n个点(编号为1~n)的无向图,初始时图中没有边。
    
    现在要进行m个操作,操作共有三种:
    
    “C a b”,在点a和点b之间连一条边,a和b可能相等;
    “Q1 a b”,询问点a和点b是否在同一个连通块中,a和b可能相等;
    “Q2 a”,询问点a所在连通块中点的数量;
    输入格式
    第一行输入整数n和m。
    
    接下来m行,每行包含一个操作指令,指令为“C a b”,“Q1 a b”或“Q2 a”中的一种。
    
    输出格式
    对于每个询问指令”Q1 a b”,如果a和b在同一个连通块中,则输出“Yes”,否则输出“No”。
    
    对于每个询问指令“Q2 a”,输出一个整数表示点a所在连通块中点的数量
    
    每个结果占一行。
    
    数据范围
    1≤n,m≤105
    输入样例:
    5 5
    C 1 2
    Q1 1 2
    Q2 1
    C 2 5
    Q2 5
    输出样例:
    Yes
    2
    3
    */
    
    int n, m;
    
    set<int> ss[100010];
    
    int cnt[100010];
    
    int main()
    {
        cin >> n >> m;
    
        for (int i = 1; i <= n; i++) {
            ss[i].insert(i);
            cnt[i] = 1;
        }
    
        for (int i = 0; i < m; i++) {
            char op[10];
            cin >> op;
            if (op[0] == 'C') {
                int a, b;
                cin >> a >> b;
    
                while (a != *ss[a].begin()) {
                    a = *ss[a].begin();
                }
                while (b != *ss[b].begin()) {
                    b = *ss[b].begin();
                }
    
                if(a !=b){
                    if(a < b){
                        cnt[a] += cnt[b];
                        ss[b].insert(a);
                    }
                    else{
                        cnt[b] += cnt[a];
                        ss[a].insert(b);
                    }
                }
            }
            else if (op[0] == 'Q'&& op[1] == '1') {
                int a; int b;
                cin >> a >> b;
    
                while (a != *ss[a].begin()) {
                    a = *ss[a].begin();
                }
                while (b != *ss[b].begin()) {
                    b = *ss[b].begin();
                }
    
                if (a == b) cout << "Yes" << endl;
                else cout << "No" << endl;
    
            }
            else if (op[0] == 'Q'&& op[1] == '2') {
                int a;
                cin >> a;
    
                while (a != *ss[a].begin()) {
                    a = *ss[a].begin();
                }
                cout << cnt[a] << endl;
            }
        }
    }
    
    
    
    作者:itdef
    链接:https://www.acwing.com/solution/content/14781/
    来源:AcWing
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    算法2

    正规并查集做法

    同样的 相同集合元素个数的记录也是要注意

    序号小的统计记录不重复的记录下之后的所有大序号元素的个数。

    序号大的元素记录里不要统计小序号元素个数,避免重复。

    C++ 代码

    #include <iostream>
    
    
    using namespace std;
    
    const int N = 100010;
    
    int n,m;
    int p[N],siz[N];
    
    int find(int x){
        if(p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    
    int main()
    {
        cin >> n >>m;
        for(int i = 1;i <= n;i++){
            p[i] = i;
            siz[i] = 1;
        }
    
        while(m--){
            string op;
            int a,b;
            cin >> op;
    
            if(op == "C"){
                cin >> a >> b;
                a= find(a); b = find(b);
                if(a != b){
                    p[a] = b;
                    siz[b] += siz[a];
                }
            }else if( op == "Q1"){
                cin >> a>> b;
                if(find(a) == find(b)) cout << "Yes" << endl;
                else cout << "No"<< endl;
            }else{
                cin >> a;
                cout << siz[find(a)] << endl;
            }
        }
    
    
    
        return 0;
    }
    
    
    
    作者:itdef
    链接:https://www.acwing.com/solution/content/14781/
    来源:AcWing
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    linux中shell变量$#,$@,$0,$1,$2的含义解释
    oracle数据库教程从入门到精通
    ORA01078: failure in processing system parameters 启动oracle数据库时报错
    Linux中文显示乱码问题以及中文输入法安装问题
    .tar.xz文件的解压
    两个rpm文件包存在互相依赖关系时,需要同时安装,解决办法如下
    #include sys/xxx.h头文件说明
    Linux下DIR_dirent_stat等结构体详解
    创建共享无线网
    Linux 磁盘“Block Size”研究
  • 原文地址:https://www.cnblogs.com/itdef/p/13130223.html
Copyright © 2011-2022 走看看