天梯赛 · 并查集

(1)朴素并查集:=》只判连通

cpp 复制代码
int p[N];              // 存储每个点的祖宗节点

// 查找 + 路径压缩(核心)
int find(int x)
{
    if (p[x] != x) 
        p[x] = find(p[x]);  // 路径直接挂到根节点
    return p[x];
}

// 初始化:每个点自己是根
for (int i = 1; i <= n; i ++ ) 
    p[i] = i;

// 合并 a 和 b 所在集合
p[find(a)] = find(b);

(2)带集合大小的并查集:=》统计集合元素个数(连不连通 + 集合多大)

cpp 复制代码
int p[N], size[N];    
// p[]:存储每个点的祖宗节点
// size[]:只有祖宗节点有效,表示当前集合的元素数量

// 查找 x 的根节点 + 路径压缩
int find(int x)
{
    if (p[x] != x) 
        p[x] = find(p[x]);
    return p[x];
}

// 初始化:每个点自己是根,集合大小为 1
void init(int n)
{
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        size[i] = 1;
    }
}

// 合并 a 和 b 所在的集合
void merge(int a, int b)
{
    int fa = find(a);
    int fb = find(b);
    if (fa != fb)
    {
        // 先更新集合大小,再修改父节点(顺序不能变)
        size[fb] += size[fa];
        p[fa] = fb;
    }
}

(3)维护到祖宗节点距离的并查集:=》维护点到根的距离/关系(连不连通 + 两点之间距离 / 关系)

cpp 复制代码
int p[N], d[N];        
// p[x]:存储节点 x 的父节点
// d[x]:存储 x 到其父节点 p[x] 的距离/权值(find后表示x到根节点的距离)

// 查找 x 的根节点 + 路径压缩 + 维护距离
int find(int x)
{
    if (p[x] != x)
    {
        // 先递归找到根节点 u
        int u = find(p[x]);
        // 更新 x 到根节点的距离
        d[x] += d[p[x]];
        // 路径压缩:直接把 x 挂到根节点上
        p[x] = u;
    }
    return p[x];
}

// 初始化:每个节点自己是根,到父节点距离为 0
void init(int n)
{
    for (int i = 1; i <= n; i ++ )
    {
        p[i] = i;
        d[i] = 0;
    }
}

// 合并 a 和 b 所在集合(根据题目自定义 distance)
void merge(int a, int b, int distance)
{
    int fa = find(a);
    int fb = find(b);
    if (fa != fb)
    {
        p[fa] = fb;
        d[fa] = distance;  // 核心:设置根 fa 到根 fb 的权值
    }
}

L2-024 部落

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;
int p[N];
int find(int x){
    if(p[x]!=x){
        p[x]=find(p[x]);
    }
    return p[x];
}
int main(){
    int n;
    int maxnum = 0;
    if(!(cin>>n)) return 0;
    for(int i = 0;i<N;i++) p[i] = i;
    for(int i = 0 ;i <n;i++){
        int k;
        if(!(cin>>k)) return 0;
        vector<int> a(k);
        for(int j = 0;j<k;j++ ){
            int x;
            cin>>x;
            if(x>maxnum) maxnum = x;
            a[j] = x;
        }
        if(k<2) continue;
     
        for(int j = 0;j<k-1;j++){
            int x = find(a[j]);
            int y = find(a[j+1]);
            if(x!=y){
                p[y] = x;
            }
        }
    }
    set<int> mp;
    //p[i] = 父节点,不一定是根
    //find(i) = 一定是根
    for(int i = 1;i<=maxnum;i++){
        mp.insert(find(i));
    }
    cout<<maxnum<<" "<<mp.size()<<endl;
    int q;
    cin>>q;
    while(q--){
        int x,y;
        cin>>x>>y;
        if(find(x)==find(y)) cout<<"Y\n";
        else cout<<"N\n";
    }
    return 0;
}

L3-003 社交集群

cpp 复制代码
#include<iostream>
#include<map>
#include<set>
using namespace std;
int f[1005], p[1005];
map<int, int> mp;
multiset<int, greater<int>> st;
int find(int x){
    if(f[x]==x) return f[x];
    return f[x]=find(f[x]);
}
void merge(int x, int y){
    int a=find(x), b=find(y);
    if(a!=b) f[b]=a;
}
int main(){
    for(int i=0; i<1005; i++) f[i]=i;
    char _;
    int n, k, h;
    cin >> n;
    for(int i=1; i<=n; i++){
        cin >> k >> _ >> p[i];
        while(--k){
            cin >> h;
            merge(p[i], h);
        }
    }for(int i=1; i<=n; i++) mp[find(p[i])]++;
    for(auto q:mp) st.insert(q.second);
    cout << st.size() << "\n" << *st.begin();
    st.erase(st.begin());
    for(auto q:st) cout << ' ' << q;
    cout << "\n";
}
相关推荐
仍然.2 小时前
算法题目---模拟
java·javascript·算法
三道渊4 小时前
C语言:文件I/O
c语言·开发语言·数据结构·c++
kali-Myon4 小时前
CTFshow-Pwn142-Off-by-One(堆块重叠)
c语言·数据结构·安全·gdb·pwn·ctf·
潇冉沐晴4 小时前
DP——背包DP
算法·背包dp
逆境不可逃5 小时前
LeetCode 热题 100 之 543. 二叉树的直径 102. 二叉树的层序遍历 108. 将有序数组转换为二叉搜索树 98. 验证二叉搜索树
算法·leetcode·职场和发展
计算机安禾5 小时前
【数据结构与算法】第19篇:树与二叉树的基础概念
c语言·开发语言·数据结构·c++·算法·visual studio code·visual studio
副露のmagic5 小时前
哈希章节 leetcode 思路&实现
算法·leetcode·哈希算法
csuzhucong5 小时前
puzzle(1037)黑白、黑白棋局
算法
XiYang-DING5 小时前
【LeetCode】链表 + 快慢指针找中间 | 2095. 删除链表的中间节点
算法·leetcode·链表