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驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    稳扎稳打Silverlight(13) 2.0交互之鼠标事件和键盘事件
    稳扎稳打Silverlight(17) 2.0数据之详解DataGrid, 绑定数据到ListBox
    再接再厉VS 2008 sp1 + .NET 3.5 sp1(2) Entity Framework(实体框架)之详解 Linq To Entities 之一
    稳扎稳打Silverlight(8) 2.0图形之基类System.Windows.Shapes.Shape
    稳扎稳打Silverlight(11) 2.0动画之ColorAnimation, DoubleAnimation, PointAnimation, 内插关键帧动画
    稳扎稳打Silverlight(21) 2.0通信之WebRequest和WebResponse, 对指定的URI发出请求以及接收响应
    稳扎稳打Silverlight(16) 2.0数据之独立存储(Isolated Storage)
    稳扎稳打Silverlight(9) 2.0画笔之SolidColorBrush, ImageBrush, VideoBrush, LinearGradientBrush, RadialGradientBrush
    稳扎稳打Silverlight(23) 2.0通信之调用WCF的双向通信(Duplex Service)
    游戏人生Silverlight(1) 七彩俄罗斯方块[Silverlight 2.0(c#)]
  • 原文地址:https://www.cnblogs.com/itdef/p/13130223.html
Copyright © 2011-2022 走看看