并查集

核心操作:

1、将两个集合合并
2、询问两个数是否在一个集合中

找父亲节点+路径压缩优化

核心代码:

int find(int x)  //返回x的祖宗结点 + 路径优化 
{
    if(p[x]!=x) p[x] = find(p[x]);  // p[x]!=x,说明不是祖宗结点
    return p[x];
}
 return p[x]==x ? x : find(p[x]);

转载于:https://blog.csdn.net/wmy0217_/article/details/104972191

常见题型

查询合并、连通块、道路连接、带权的连通图

HDU 1232题

 

 题意:将所有独立的集合连接起来还需要几条路,那只要找到独立集合个数-1就可以

#include<bits/stdc++.h>
using namespace std;
#define IO ios_base::sync_with_stdio(false)
#define forn(i,n) for(int i=0;i<n;i++)
#define form(i,n) for(int i=1;i<=n;i++)
#define N 100005

int p[N];

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

void combine(int a,int b)
{
    int fa=find(a);
    int fb=find(b);
    if(fa!=fb)p[fa]=fb;
}

int main()
{
    IO;
    int n,m;
    while(cin>>n){
        if(n==0)break;
        cin>>m;
        int ans=0;
        form(i,n)p[i]=i;
        forn(i,m){
            int a,b;
            cin>>a>>b;
            combine(a,b);
        }
        form(i,n)if(p[i]==i)ans++;
        cout<<ans-1<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/angelliu/p/13407416.html