1. 程式人生 > 其它 >查並集Disjoint Set(不相交的集合)

查並集Disjoint Set(不相交的集合)

技術標籤:學習隨更

目錄

常見兩種操作:

1、合併兩個集合
2、查詢某個元素屬於哪個集合

實現方法一(常用): 每個集合用一棵“有根樹”表示

  • 定義陣列Set[1,n];
  • Set[ i ] = i ;則 i 表示本集合,並使集合對應樹的根
  • Set[ i ] = j ;若 j 不等於 i ,則 j 是 i 的父節點

舉個例子:

Set(i)1232134334
i12345678910

在這裡插入圖片描述

具體操作:
1、查:最壞情況O(n)

findx(x){
    while(x!=
Set[x])x=Set[x];//找父節點“找領導” return x; }

2、並:O(1)

mergeset(a,b){//a,b都是根節點(他倆是各自的領導)
	Set[a]=b;//表示把a的領導換成了b;
}

避免最壞的情況:(一般不需要)
方法:將深度小的樹合併到深度大的樹上(深度是要另外用陣列計數的)
效果:任意順序合併後,包含k個節點的樹的最大高度不超過 lg(k);
1、查:

findx(x){
    while(x!=Set[x])x=Set[x];//找父節點“找領導”
    return x;
}

2、並:

mergeset(a,b){//a,b都是根節點(他倆是各自的領導)
if(h[a]==h[b]){ h[a]++; Set[b]=a; } else if(h[a] <h[b])Set[a]=b; else Set[b]=a; }

實現方法二(不常用):

用編號最小的元素標記所在集合;
定義一個數組Set[1,n],其中Set[i]表示元素i所在的集合;
舉個例子:

Set(i)1214261622
i12345678910

則不相交集合:
{1,3,7},{4},{2,5,9,10},{6,8}
課件每個不相交集合的第一個元素所對應的Set(0)就為該集合中所有元素所對應的值

具體操作:
1、查:O(1)

findx(x){return Set[
x];}

2、合併:O(n)

mergeset(a,b){
    i=min(a,b);
    j=max(a,b);
    for(k=1;k<=n;k++){
       if(Set[k]==j)Set[k]=i;
    }
}

查並集的簡單應用

最小生成樹

最小生成樹

例題

HDU 1233

#include <bits/stdc++.h>
#define ll long long

using namespace std;

//最小生成樹問題
int s[110];

struct node {int a, b, d;}c[5000];
bool cmp(node x,node y){return x.d<y.d;}

int findx(int x){//查並集中的查
    while(x!=s[x])x=s[x];
    return x;
}

int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n;
    while(scanf("%d",&n),n){
        int m=n*(n-1)/2;
        for(int i=1;i<=m;i++)scanf("%d%d%d",&c[i].a,&c[i].b,&c[i].d);
        sort(c+1,c+1+m,cmp);//排序;將邊的權值從小到大排序;
        for(int i=1;i<=n;i++)s[i]=i;//查並集一定的步驟:“根的初始化”
        
        int ans=0,g=0;
        for(int i=1;i<=m;i++){
            if(findx(c[i].a) !=findx(c[i].b) ){//只有根節點不同才能進行;否則就不是樹就成環了
                ans+=c[i].d;
                s[ findx(c[i].a) ]=findx(c[i].b);//合併
                g++;if(g==n-1)break;//這一步可有可無;這一步剪枝;因為是樹所以就是n-1條邊;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

別人的題解,加了個ran陣列 記錄深度 優化查並集,但是這給題n<100沒必要加,可以學習一下別人記錄深度的做法