并查集 笔记与思路整理

算是非常基础的内容了,之前写到Kruskal的时候突然想起还没整理过。

其实就想存个板子

并查集是一种树型的数据结构,用于处理一些集合(只能是不交集)。

“感性理解”一下就是把一堆东西分成若干堆,每个东西都在且仅在其中一堆里。

具体实现的话利用一个father数组,指向该元素的父亲节点。初始时所有元素的father均为它自己,表示每个元素均各自在自己的集合里。若两个元素在同一个集合中,它们的祖先就为同一个。

主要是两个函数:join和find。

先说一下find:

int find(int x) {
    if(father[x]!=x) father[x] = Find(father[x);
    return father[x];
}

很好理解,如果x是自己的父亲,它就是自己集合的根节点,否则就逐层查询到根节点为止(顺便路径压缩——把集合中的点都直接连在根节点下)。这个函数主要是用来通过看两个元素的祖先是否一致,判断两个元素是否在同一个集合中。

 然后是join:

void Join(int x, int y){
    int fx = Find(x), fy = join(y);
    if(fx != fy) father[fy] = fx;
    return;
}

这里需要想象一下,假如要把两个很大的集合合并起来,最简单的操作就是直接把一个集合的根节点并到另一个集合下。(至于结构会很混乱嘛……下次Find的时候再整理就行了)

代码实现:

#include <bits/stdc++.h>
using namespace std;
int father[10010];
int Find(int x) {
    if(father[x]!=x) father[x]=Find(father[x]);
    return father[x];
}
void Join(int x, int y){
    int fx = Find(x), fy = join(y);
    if(fx != fy) father[fy] = fx;
    return;
}
int main() {
    for(int i=1; i<=10000; i++) father[i]=i;
    int n, m, x, y;
    scanf("%d %d", &n, &m);
    while(m--) {
        scanf("%d %d",&x,&y);
        Join(x, y);
    }
    int p;
    scanf("%d", &p);
    while(p--) {
        scanf("%d %d",&x,&y);
        if(Find(x) != Find(y)) printf("F
");
        else printf("T
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/miserweyte/p/11408458.html