首页 > 其他分享 >并查集

并查集

时间:2023-01-03 20:22:29浏览次数:55  
标签:10 int 查集 find 带货 集合 节点

并查集

操作:

  1. 将两个集合合并。
  2. 询问两个元素是否在一个集合中。

基本原理:

每个集合用一棵树来表示。树根的编号就是整个集合的编号。每个节点的值储存它的父节点编号,\(p[x]\) 表示 \(x\) 的父节点。

问题:

\(Question1\): 如何判断是不是根节点?

\(Answer\): 判断 \(p[x]\) 是否等于 \(x\) ,即 \(x\) 的父节点是否是它本身。

\(Question2\): 如何求 \(x\) 的集合编号(根节点)?

\(Answer\): 朴素可以通过 while (p[x] != x) x = p[x] 求得。即当 \(x\) 不是根节点时,不断向上求直到是根节点。

\(Question3\): 如何合并两个集合?

\(Answer\): 若 \(a\) 是 \(x\) 的根节点编号,\(b\) 是 \(y\) 的根节点编号,令 \(p[a] = b\) ,即让 \(x\) 的集合的根节点的父节点变成 \(y\) 集合的根节点。

重要优化:路径压缩

在上面的 \(Question2\) 中我们可以发现,在查找一个节点的根节点时,需要不断向上找,耗时长。我们可以通过路径压缩,让每个节点直接指向根节点。

这里需要利用递归实现。

int find(int x)
{
    return x == p[x] ? p[x] : p[x] = find(p[x]);
}

\(\mathrm{find}\)函数可以实现寻找根节点的同时进行路径压缩。





例题:带货援助

题目描述

张三学姐找人帮忙带货。有 \(n\) 个带货达人,已知让每个带货达人帮忙带货的价格是 \(c_i\),如果花钱雇了一个带货达人,因为他们之间经常互动一起带货,所以花钱雇的这个带货达人的朋友(朋友也是 \(n\) 个带货达人中的一员)也会帮忙免费带货,已知有 \(n\) 个人, \(m\) 对朋友。

请你可以帮她算一下最少可以只花多少钱就可以让所有带货达人都帮忙带货。

输入格式

第一行包含两个整数 \(n\) 和 \(m\) \((1 ≤ n ≤ 10^5, 0 ≤ m ≤ 10^5)\),分别表示张三学姐认识的带货达人的数量,以及存在多少对的朋友关系。

第二行包含 \(n\) 个整数 \(c_i\) \((0 ≤ c_i ≤ 10^9)\) 表示雇佣第 \(i\) 个带货达人需要的人民币,以便开始带货。

接下来的 \(m\) 行,每行包含两个数 \((x_i, y_i)\),表示带货达人 \(x_i\) 和 \(y_i\) 是朋友关系 \((1 ≤ x_i, y_i ≤ n, x_i ≠ y_i)\)。数据保证,每对朋友最多被列出一次。

输出格式

输出一个数,表示张三学姐雇佣所有带货达人的最少金钱。

输入输出样例

输入 输出
5 2
2 5 3 5 9
1 4
4 5
10
10 0
1 2 3 4 5 6 7 8 9 10
55
10 5
1 6 2 7 3 8 4 9 5 10
1 2
3 4
5 6
7 8
9 10
15





分析:

按照题意,我们需要将是朋友的带货达人放在一个集合里,并且只需要花费这个集合里所需的最小的价值就能让这个集合所有的带货达人帮忙带货,对于没有朋友关系的带货达人,则只能花费相应的金钱让他帮忙带货。

所以我们用并查集,先将有朋友关系的带货达人的编号放进同一个集合,同时,我们可以把根节点的值变为其中最小的那个价值。最后,我们遍历所有的集合,求根节点的价值之和。(单独的带货达人,根节点就是他自己的编号)


#include <iostream>
using namespace std;
const int N = 1e5+10;
int a[N], p[N];
int find(int x)
{
    return x == p[x] ? p[x] : p[x] = find(p[x]);
}
int main()
{
    int n, m;
    cin >> n >> m;
    for (int i=1;i<=n;i++) p[i] = i; //初始化根节点的值
    for (int i=1;i<=n;i++) cin >>a[i];
    while (m--)
    {
        int x, y;
        cin >> x>> y;
        if (find(x) != find(y))
        {
            if (a[find(x)] > a[find(y)]) p[find(x)] = find(y); //集合合并操作,让需要金钱更多的带货达人的根节点变为需要金钱更少的带货达人
            else p[find(y)] = find(x);
        }
    }
    long long ans = 0;
    for (int i=1;i<=n;i++)
    {
        if (p[i] == i) ans += a[i];
    }
    cout << ans << endl;
}

原题链接:

标签:10,int,查集,find,带货,集合,节点
From: https://www.cnblogs.com/juniexd/p/17023277.html

相关文章

  • Parity Game(奇偶游戏)(POJ1733、AcWing 239)(并查集)(扩展域写法+边带权写法)
    题目小A和小B在玩一个游戏。首先,小A写了一个由0和1组成的序列S,长度为N。然后,小B向小A提出了M个问题。在每个问题中,小B指定两个数l和r,小A回答S[l......
  • 【LeetCode周赛-312】子数组按位与最大值、并查集(图)
    周赛链接:​​​https://leetcode.cn/contest/weekly-contest-312/​​A.2418.按身高排序题目描述:给你一个字符串数组names,和一个由互不相同的正整数组成的数组heig......
  • 「并查集」改变道路
    本题为1月1日22寒假集训每日一题题解题目来源:(未知)题面题目描述有n个城市和m条道路,每条道路连接两个城市。每条道路都是单向的,但你可以决定每条道路的方向。一个城......
  • E. Cross Swapping-带权并查集cf1713
    E.CrossSwappinghttps://codeforces.ml/problemset/problem/1713/E题意给定n*n的矩阵每次可以选定第k行和第k列交换位置操作次数不限求最小字典序的矩阵思路让......
  • TZOJ 5782: 亲戚/6310: 亲戚2 并查集/路径压缩/优化
    先来看看代码清单:(1)初始化for(inti=1;i<=n;i++)f[i]=i;//初始化每个的爹是自己因为每个元素属于单独的一个集合,所以每个元素以自己作为结点(2)寻找根结点编号并压......
  • P1024 [NOI2001] 食物链【种类并查集】
    题意P1024简化题意:给定\(n\)和\(k(n\leqslant5\times10^4,k\leqslant10^5)\),表示有\(n\)个动物,\(k\)个描述,其中:\(n\)个动物分别属于\(A,B,C\)中的一种,定义......
  • 数据结构:并查集 学习笔记
    数据结构:并查集学习笔记基础知识并查集是一种树形数据结构。在全国青少年信息学奥林匹克系列竞赛大纲中难度为6,是提高级中学习的数据结构。并查集的基本操作:查询一......
  • 并查集
    title:并查集date:2022-11-1511:49:57tags:算法本文章遵守知识共享协议CC-BY-NC-SA,转载时须在文章的任一位置附上原文链接和作者署名(rickyxrc)。推荐在我的个人博......
  • 带权并查集
    被老师拖来讲数据结构了带权并查集带权并查集,顾名思义,就是在并查集中加上权值,点权和边权实际上是等价的,因为并查集实际上是多棵树组成的,树上的每个节点,都只有一个父节点,......
  • 一个并查集对象
    实现并查集的查找、合并、类别sizeclassUF{constructor(n){this.parent=Array(n)this.size=[]for(leti=0;i<n;i++){......