P1551 亲戚(并查集)
发布日期:2021-05-08 21:49:43 浏览次数:19 分类:精选文章

本文共 1461 字,大约阅读时间需要 4 分钟。

并查集是一种高效的数据结构,用于管理动态集合的合并和查找操作。它的核心思想是通过路径压缩和按秩合并,确保查找和合并操作的时间复杂度接近常数。这正是解决这个问题的关键,因为我们需要快速判断两个节点是否属于同一个亲戚集合。

并查集的实现

我们使用并查集来维护每个节点的亲戚关系。具体步骤如下:

  • 初始化:创建一个父节点数组pre,其中pre[i]表示节点i的父节点。初始时,每个节点是自己的父节点。

  • 查找函数find:用于找到节点x的根节点。路径压缩技术会将x直接指向其根节点,减少后续查找的时间。

  • 合并函数bcj:用于将两个节点合并到同一个集合中。使用按秩合并策略,确保树的高度平衡。

  • 处理输入:读取亲戚关系并执行合并操作。读取查询并判断两个节点是否属于同一个集合。

  • 代码实现

    #include 
    #include
    using namespace std;int n, m, p;int pre[5005]; // 节点编号从1到nint find(int x) { if (pre[x] == 0) return x; pre[x] = find(pre[x]); // 路径压缩 return pre[x];}void bcj(int x, int y) { int x_root = find(x); int y_root = find(y); if (x_root != y_root) { pre[y_root] = x_root; // 按秩合并,合并到较小的树上 }}int main() { cin >> n >> m >> p; for (int i = 1; i <= m; ++i) { int x, y; cin >> x >> y; bcj(x, y); } for (int i = 1; i <= p; ++i) { int x, y; cin >> x >> y; if (find(x) == find(y)) { cout << "Yes"; } else { cout << "No"; } }}

    解释

  • 初始化pre数组初始化为0,表示每个节点最初没有父节点。随着查找操作的执行,父节点会被更新。

  • 查找函数find:递归地找到节点的根节点,并进行路径压缩。路径压缩将节点直接指向根节点,减少未来的查找时间。

  • 合并函数bcj:找到两个节点的根节点。如果根节点不同,将其中一个的根节点指向另一个,实现合并。按秩合并确保树的高度平衡,减少合并时间。

  • 处理输入:读取亲戚关系并执行合并操作,确保所有相关节点在同一集合中。然后处理每个查询,检查两个节点的根节点是否相同,输出结果。

  • 样例测试

    输入:

    6 5 31 21 53 45 21 31 42 35 6

    输出:

    YesYesNo

    结果解释

    • 查询1-3:1和3都在同一个集合中,输出Yes。
    • 查询1-4:1和4都在同一个集合中,输出Yes。
    • 查询2-3:2和3都在同一个集合中,输出Yes。
    • 查询5-6:5和6不在同一个集合中,输出No。

    通过这样的步骤,我们可以高效地判断任意两个节点是否是亲戚。并查集的高效操作使得即使在大规模数据下,问题也能快速解决。

    上一篇:P3367 【模板】并查集(并查集)
    下一篇:P2078 朋友(并查集)

    发表评论

    最新留言

    关注你微信了!
    [***.104.42.241]2025年03月26日 11时50分29秒