UnionFind
キーワード
概要
Union Find はグループ分けを効率的に管理する, 根付き木を用いたデータ構造.
構造
type UnionFind struct {
n int
root []int
}
操作
操作 | 引数 | 返り値 |
---|---|---|
constructor | n | UnionFind |
isSame | x, y | x, y を含むグループが同じか |
unite | x, y | x, y を含むグループを併合する |
find(root) | x | x の根を返す |
グループの代表者を root で管理し, 代表者を根にもつ木を表現する.
計算量
操作 | 計算量(ならし) |
---|---|
constructor | |
isSame | |
unite | |
find(root) |
ここで, はアッカーマン関数の逆関数. 実質的に と考えて良い.
ならし計算量とは、ある操作を複数回行った場合の合計の計算量を指す。
ここでは、find
を 回、unite
を 回任意の順番で行った場合の合計の計算量が となることから、それぞれの操作の計算量を と表現している。
実装
- 高速化
type UnionFind struct {
n int
root []int
sizes []int
}
func newUnionFind(n int) UnionFind {
root := make([]int, n)
sizes := make([]int, n)
for i := 0; i < n; i++ {
root[i] = i
sizes[i] = 1
}
uf := UnionFind{n: n, root: root, sizes: sizes}
return uf
}
func (u *UnionFind) find(x int) int {
if u.root[x] == x {
return x
}
u.root[x] = u.find(u.root[x]) // 再帰で根に直接繋ぎ直す
return u.root[x]
}
func (u *UnionFind) unite(x, y int) {
x = u.find(x) // xを根に書き換え
y = u.find(y) // yを根に書き換え
if x == y {
return
}
if u.size(x) < u.size(y) {
x, y = y, x
} // xのグループの要素数がyのグループの要素数より小さくなるようにswap
u.sizes[x] += u.sizes[y]
u.root[y] = x
}
func (u *UnionFind) isSame(x, y int) bool {
return u.find(x) == u.find(y)
}
func (u *UnionFind) size(x int) int {
return u.sizes[u.find(x)]
}
- 高速化 + 省メモリ
type UnionFind struct {
n int
root []int
}
func newUnionFind(n int) UnionFind {
root := make([]int, n)
for i := 0; i < n; i++ {
root[i] = -1
}
uf := UnionFind{n: n, root: root}
return uf
}
func (u *UnionFind) find(x int) int {
if u.root[x] < 0 { // 負の場合は根
return x
}
u.root[x] = u.find(u.root[x]) // 再帰で根に直接繋ぎ直す
return u.root[x]
}
func (u *UnionFind) unite(x, y int) {
x = u.find(x) // xを根に書き換え
y = u.find(y) // yを根に書き換え
if x == y {
return
}
if -u.root[x] < -u.root[y] {
x, y = y, x
} // xの集合の要素数の方が大きいようにスワップ
u.root[x] += u.root[y]
u.root[y] = x
}
func (u *UnionFind) isSame(x, y int) bool {
return u.find(x) == u.find(y)
}
func (u *UnionFind) size(x int) int {
return -u.root[u.find(x)]
}
省メモリバージョンでは、root の値が負かどうかで根かどうかを判定している。
- 負の場合は根であり、その値の絶対値がそのグループの要素数を表す。
- 正の場合は親のインデックスを表す。
例題
- 典型 90 | 012 - Red Painting(★4) (opens in a new tab)
- 鉄則本 | A67 - MST (Minimum Spanning Tree) (opens in a new tab)
引用
- https://zenn.dev/isseii/articles/algo-union-find (opens in a new tab)
- https://algo-method.com/descriptions/136 (opens in a new tab)
- https://37zigen.com/union-find-complexity-1/#find (opens in a new tab)
- https://qiita.com/kopricky/items/3e5847ab1451fe990367 (opens in a new tab)
- https://atcoder.github.io/ac-library/document_ja/dsu.html (opens in a new tab)