• 并查集的基本定义


    并查集适合维护具有非常强烈的传递性质,或者具有连通集合性质。

    传递性质

    具有传递效应的性质,比如A传递给B一个性质或者条件,让B同样拥有这个性质或者条件,这就是传递性。

    连通集合性质

    连通集合性,和数学概念上的的集合定义类似,比如A和B同属于一个集合,B和C同属于一个集合,那么A,B,C属于同一个集合。

    初始化操作:

    每个子对象的父节点初始化为自己

    合并:

    合并不同的集合

    查找

    判断两个子对象是否在同一个集合中

    路径压缩

    每一个集合可能包括了很多对象,有些对象可能存在一条很长的关系线,这时候把该集合所有对象的父节点转化为该集合的父节点,这就是路径压缩。

    #include<iostream>
    using namespace std;
    int pre[1005];//每个点的前导点
    int route[2005][2];
    //可以配对的路线
    int sum = 0;
    //符合条件的 即关键点的数量
    
    //查找
    int find(int x)
    {
        int r = x;
        while (pre[r] != r)
            r = pre[r];
        int i = x, j;
        while (i != r)//路径压缩算法
        {
            j = pre[i];//在改变他的前导点时,存储他的值
            pre[i] = r;
            i = j;//改变他的前导点为根节点
        }
        return r;
    }//
    递归方法:

    /*int find(int k)
    {
    if(f[k]==k)
    return k;
    return f[k]=find(f[k]);
    }*/

    void join(int x, int y)
    //组合
    {
        int fx = find(x), fy = find(y);//分别记录x,y的根节点
        if (fx != fy)//如果他们的根节点相同,则说明他们不是连通图
            pre[fx] = fy;//将x的根结点 同 相连接
    }
    
    int main()
    {
        int n, m;
        cin >> n>>m;//n表示站点的个数,m表示链路的个数
    
        for (int i = 0; i < m; i++)
        {
            cin >> route[i][0] >> route[i][1];
            join(route[i][0], route[i][1]);//将数据相互连接
        }
    
    
        int q1,q2;//待询问的两个点
        cin >> q1 >> q2;
    
    
        for (int ii = 0; ii < n; ii++)pre[ii] = ii;
        for (int j = 0; j < m; j++)
        {
    
                join(route[j][0], route[j][1]);
        }
        int a = find(q1);
        int b = find(q2);
        //如果边全部存在时不可达,则输出 -1;
        if (a != b)
        {
            cout << "-1" << endl;
        }
    
        else
        {
            for (int i = 1; i <= n; i++)
    //枚举每一个点
            {
                if (i == q1 || i == q2)continue;
    //如果是被询问的点,跳过,无需遍历   此处是最关键的部分
                for (int j = 1; j <= n; j++)pre[j] = j;
    //将每一个初始化
    
                for (int j = 0; j < m; j++)
                {
                    if (route[j][0] == i || route[j][1]==i)continue;
    //去除当前点互相关联的边   解决问题的关键
                    int a = find(route[j][0]);
                    int b = find(route[j][1]);
                    if (a > b) { a ^= b; b ^= a; a ^= b; };//交换
                    if (a != b)pre[b] = a;
    //以较小的点作为父节点
                }
                int a = find(q1);
                int b = find(q2);
                if (a != b)sum++;
                }
                cout<<sum<<endl;
            }
            return 0;
    }
  • 相关阅读:
    Asp.Net生成二维码(中间加logo)
    简单的图片上传
    C#读取路径
    Asp.Net读取配置文件
    C#监听服务
    jQuery 遍历--siblings() 方法、each() 方法
    Window 6大内置对象
    MySQL中几个重要的参数
    DNS构建实战(下篇)
    DNS构建实战(上篇)
  • 原文地址:https://www.cnblogs.com/flyljz/p/11626275.html
Copyright © 2020-2023  润新知