并查集及其优化

总结一下并查集吧。
学了好多次结果都没记住。
啊~~~~~~


下面介绍一个我比较看得过去的并查集入门介绍

下面是他给出的一个代码模板

#include <iostream>
using namespace std;
const int N = 10010;

int f[N];
int high[N]; // 保存每个朋友圈的高度,初始时都是 0 

/*
 * 将表示朋友圈的数组初始化,即将所有人的“朋友祖先”都设置为自己的 id ,
 * 于是就有了 n 个不同的朋友圈 
 */
void init(int n)
{
    for(int i = 1; i <= n; i++)
    {
        f[i] = i;
    }
}

// 得到 id 为 v 的人的“朋友祖先”的 id 
int getFriend(int v)
{  
    if(f[v] == v)
    {
        return v;
    }
    /*
     * 如果发现“朋友祖先”不是自己,那么他肯定被合并到别的朋友圈里面去了,
     * 那么继续调用这个函数来找这个朋友圈里面的“朋友祖先”,
     * 并且在这个过程中将找到的人都设置为同一个“朋友祖先”(因为都在同一个朋友圈里面) 
     */
    return f[v] = getFriend(f[v]);
}

/**
 * 将两个人所在的两个朋友圈合并为一个朋友圈 
 * 这里通过两个朋友圈的高度来决定合并方式 
 */
void merge(int a, int b)
{
    int t1 = getFriend(a); // 得到左边的人的“朋友祖先” 
    int t2 = getFriend(b); // 得到右边的人的“朋友祖先” 
    // 两个人的“朋友祖先”不一样,合并两个朋友圈 
    if(t1 != t2) {  
        // 如果左边的朋友圈的高度大于右边的朋友圈的高度,
        // 那么将右边的朋友圈合并到左边的朋友圈中 
        if (high[t1] > high[t2])
        {
            f[t2] = t1;
        // 否则就把左边的朋友圈合并到右边的朋友圈中 
        }
        else
        {
            f[t1] = t2;
            // 如果当前两个朋友圈的高度相等,那么合并之后的朋友圈高度要加1
            if (high[t1] == high[t2])
            {
                high[t2]++;
            }
        }
    }
}

int main()
{
    int n, m, k;
    cin >> n >> m >> k;
    int x, y;
    init(n);

    for(int i = 0; i < m; i++)
    {
        cin >> x >> y;
        merge(x, y);
    }

    /*
     * 输出合并之后的数组情况
     */
    for(int i = 1; i <= n; i++)
    {
        if(i != 1)
        {
            cout << " ";
        }
        cout << f[i];
    }
    cout << endl;

    for(int i = 0; i < k; i++)
    {
        cin >> x >> y;
        // 如果两个人的“朋友祖先”不相同,证明他们不在同一个朋友圈内,也就不是朋友
        if(getFriend(x) != getFriend(y))
        {
            cout << "no" << endl; 
        }
        else
        {
            cout << "yes" << endl;
        }
    }
    return 0;
} 

上面的代码是针对特定题目的,而且注释巨多。
下面我总结一个比较简洁的代码模板吧,
我也借机熟悉一下代码,嘿嘿~

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;

int f[maxn];//每个节点的父节点
int high[maxn];//每个节点下属节点的高度(注意是高度不是个数)


void Init()//初始化函数
{
    memset(high,0,sizeof(high));
    for(int i=0;i<maxn;i++) f[i]=i;
}

int GetSet(int p)//获得p节点的根节点
{
    return (f[p]==p)? p : GetSet(f[p]);
}

void Merge(int x,int y)//x与y集合合并
{
    x = GetSet(x);
    y = GetSet(y);
    if(x != y)
    {

        if(high[x]>high[y])
        {
            f[y]=x;
        }
        else
        {
            f[x]=y;
            if(high[x]==high[y])high[y]++;
        }
    }
}
//这里是主函数
int main()
{
    int n, m, k;
    cin >> n >> m >> k;
    int x, y;
    Init();

    for(int i = 0; i < m; i++)
    {
        cin >> x >> y;
        Merge(x, y);
    }
    //输出合并之后的数组情况
    for(int i = 1; i <= n; i++)
    {
        if(i != 1) cout << " ";
        cout << f[i];
    }
    cout << endl;

    for(int i = 0; i < k; i++)
    {
        cin >> x >> y;
        //如果两个人的“朋友祖先”不相同,证明他们不在同一个朋友圈内,也就不是朋友
        if(GetSet(x) != GetSet(y)) cout << "no" << endl; 
        else cout << "yes" << endl;
    }
    return 0;
}

给一个测试数据

7 5 4
1 3
2 4
3 4
1 4
5 6
1 4
2 3
2 5
6 7

结果如下

4 4 4 4 6 6 7
yes
yes
no
no

OK

原文地址:https://www.cnblogs.com/savennist/p/13427568.html