UnionFind
DSU(disjoint set union)とも
init
- 整数 \(N\) を与えると、頂点を\(N\)個生成し全て独立にする
- 計算量は \(Ο(N)\)
unionfind
- コンストラクタ。initを呼ぶ
leader
- 頂点 \(k\) が所属する連結集合の代表元を返す
- と同時に経路圧縮する
- 計算量は \(Ο(\alpha (N))\)
\(α(x)\) はアッカーマン関数 \(Ack(x,x)\) の逆関数
\(Ack(4,4) = 2^{2^{2^{65536}}}-3\) から伺えるように、 \(\alpha (x)\) は実用上定数( \(4\) )倍と見なせるほどに収束が遅い
same
- 頂点 \(p\) と頂点 \(q\) がその時点で同じ連結成分に属しているかを調べ、同じならtrue、違うならfalseを返す
- 計算量は \(Ο(\alpha (N))\)
size
- 頂点 \(k\) が所属する連結集合のサイズを返す
- 計算量は \(Ο(1)\)
merge
- 頂点 \(p\) と頂点 \(q\) の間に辺を張る(集合を合併する)
- すでに同じ連結成分に属している場合は無視する
- 計算量は \(Ο(\alpha (N))\)
class unionfind{
// Copyright (c) 2024 0214sh7
// https://github.com/0214sh7/library/
private:
std::vector<int> par,rank,size_;
public:
void init(int N){
par.assign(N,0);
rank.assign(N,0);
size_.assign(N,1);
for(int i=0;i<N;i++){
par[i] = i;
}
}
unionfind(int N){
init(N);
}
int leader(int k){
if(par[k]==k){
return k;
}
par[k] = leader(par[k]);
return par[k];
}
bool same(int p,int q){
return leader(p)==leader(q);
}
int size(int k){
return size_[leader(k)];
}
void merge(int p, int q){
p = leader(p);
q = leader(q);
if(p==q)return;
if(rank[p]<rank[q])std::swap(p,q);
par[q]=p;
if(rank[p]==rank[q])rank[p]++;
size_[p] += size_[q];
size_[q] = 0;
}
};
使用例
実行コード
#include <bits/stdc++.h>
class unionfind{/*省略*/};
int main(void){
unionfind UF(13);
UF.merge(1,3);
UF.merge(1,5);
UF.merge(1,7);
UF.merge(1,8);
UF.merge(1,10);
UF.merge(1,12);
UF.merge(4,6);
UF.merge(4,9);
UF.merge(4,11);
std::cout << "それぞれが所属する連結成分の代表頂点\n";
for(int i=1;i<=12;i++){
std::cout << UF.leader(i) << " ";
}
std::cout << "\n\n";
std::cout << "1と同じ連結成分に属しているならo、そうでないならx\n";
for(int i=1;i<=12;i++){
std::cout << (UF.same(1,i)?"o":"x") << " ";
}
std::cout << "\n\n";
std::cout << "同じ連結成分に入っている頂点がいくつあるか\n";
for(int i=1;i<=12;i++){
std::cout << UF.size(i) << " ";
}
std::cout << std::endl;
return 0;
}
出力
それぞれが所属する連結成分の代表頂点
1 2 1 4 1 4 1 1 4 1 4 1
1と同じ連結成分に属しているならo、そうでないならx
o x o x o x o o x o x o
同じ連結成分に入っている頂点がいくつあるか
7 1 7 4 7 4 7 7 4 7 4 7
更新履歴
日時 | 内容 |
---|---|
2024/09/22 | 微細な変更 |
2024/09/18 | 実装と一部機能の関数名を変更 |
2023/06/29 | ライセンスのコメントアウトを変更 |
2021/08/31 | sizeを追加 |
2021/03/26 | 使用例、コンストラクタを追加 |
2020/04/06 | UnionFindを追加 |
確認した問題
問題 | 提出 |
---|---|
ABC157-D | 提出 |
Library Checker | 提出 |