大概又有一个多月没有更了。具体原因。。。太忙了(真的,事情太多了)本来想着考试周之后就开始更的,但因为朋友的安利和鼓动,玩了两天的游戏。。。然后有写了几天的实验报告和小论文。现在鄙人可以说自己是一个“自由人”了。
今天就当暑假正式开始了吧,开始暑假第一篇:并查集

这绝对不是一个陌生的概念,但有一说一,这玩意真的没有在课上细讲过。今天鄙人就讲讲自己对于并查集的理解。

并查集,顾名思义:合并+查询。其本职工作就是将两个集合合并和查询两个元素是否在一个集合中
常用的并查集是进过路径压缩的并查集(路径压缩。。。)。没错,就是与树和图紧密相关的路径压缩。我们可以将一个并查集看做一个树的结构。

对于每一个节点都有一个父节点p[x],当父节点等于自身时,代表找到根节点。
利用并查集如何解决三个基本问题:
问题1:如何判断树根节点?
if(p[x]=x)

问题2: 如何求x的集合编号?
while(p[x]!=x) x=p[x]

问题3: 如何合并两个集合?
px是x的集合编号,py是y的集合编号,p[px]=py即可

现在我们可以考虑一下如和进行路径压缩。其实也好想,就是基于摊销的思想。将所有节点的父节点全部指向根节点,这样就可以在近乎O(1)的时间查询到某个元素在那个集合中。

现在举个例子:

一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。
现在要进行 m 个操作,操作共有两种:
M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;

输入格式
第一行输入整数 n 和 m。
接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。

输出格式
对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No。

输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes

实现代码如下:

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010;
int p[N];
int n, m;

int find(int x)             //返回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;       //将初始的每个节点都设为根节点,表示有n个独立集合

    while (m--)
    {
        char op[2];
        int a, b;
        cin >> op >> a >> b;

        if (op[0] == 'M') p[find(a)] = find(b);        //将两个集合合并
        else
        {
            if (find(a) == find(b))              //在同一集合内
            puts("Yes");        
            else puts("No");
        }
    }
    return 0;
}
分类: 算法集

0 条评论

发表评论

Avatar placeholder

邮箱地址不会被公开。 必填项已用*标注