狠狠撸
Submit Search
Union find(素集合データ構造)
?
27 likes
?
185,562 views
A
AtCoder Inc.
Follow
Union find(素集合データ構造)の解説です
Read less
Read more
1 of 18
Download now
Downloaded 160 times
More Related Content
Union find(素集合データ構造)
1.
Union-Find (素集合データ構造)
2.
? グループ分けを管理する ? はじめ,?
個の物は全て別々のグループ ? 次の 2 種類のクエリに対応する 1. 「まとめる」 2. 「判定」 Union-Find 木の機能 1 2 3 4 5
3.
クエリ 1:まとめる ? 2
つのグループを 1 つにまとめる 1 2 1 2 1 3 2 4 6 1 2 3 4 6
4.
クエリ 2:判定 ? 2
つの要素が同じグループに属しているかを判 定する 1 3 2 4 6 5 1 と 3 → true 1 と 2 → false
5.
素朴な実現法 (1/2) ? 配列に,同じグループなら同じ数字を入れてお く 1
3 2 4 6 5 1 2 3 4 5 6 1 2 1 2 5 2
6.
素朴な実現法 (2/2) ? この方針の問題点 –
グループをまとめる際に,?(?) 時間かかってしまう – 実際には,この方針でも少しの工夫でならし ?(log ?) 時間にできます http://topcoder.g.hatena.ne.jp/iwiwi/20131226/1388062106 ? Union-Find 木は,もっと効率的に行う
7.
Union-Find 木 ? グループを,1
つの木で表現する – したがって,全体では森 1 3 2 4 6 5 1 3 2 4 6 5
8.
クエリ1:「まとめる」 ? 片方の木の根からもう片方の根に辺を張ればよ い 1 2 1 2 1 3 2 4
6 1 3 2 4 6 1 と 2 をまとめる 2 から 1 に辺を張る
9.
クエリ2:「判定」 ? 2 つの要素を上に辿って,根が同じかどうかを 見ればよい 1 3 2 4
6 5 2 と 6 → 根は共に 2 → true 1 と 4 → 根は 1 と 2 → false
10.
Union-Find 木の効率 ? 正当性:このやり方で,グループの判定はうま くできる ?
効率:最悪の場合,この方法でも ツリーが縦長になると処理が遅く なってしまう → 効率化のテクニックを導入
11.
効率化工夫 1:経路圧縮 ? 上向きに辿って再帰的に根を調べる際に,調べ たら辺を根に直接つなぎ直す ?
4 の根を調べると,2, 3, 4 の根が 1 と分かる 1 2 3 4 1 2 3 4
12.
効率化工夫 2:ランク ? 木の高さを持っておき,低い方を高い方に繋げ るようにする ?
ただし,経路圧縮と組み合わせた際,経路圧縮による高 さの減少は無視する (つまり,ランクは経路圧縮しなかった場合の高さに相当する) 1 2 3 4 5 1 2 3 4 5 ランク 3 ランク 2 ランク 3
13.
Union-Find 木の計算量 ? 2
つの工夫の両方をして ?(?(?)) – ?(?) はアッカーマン関数 ?(?, ?) の逆関数 – 相当小さい(log より小さい!) ? 片方だけでも,だいたい ?(log ?) – 経路圧縮のみが実装が楽でよい ? これらはならし計算量
14.
Union-Find 木の実装(ランク無し) ? 経路圧縮のみ(ランクは使わない) ?
par[i] = i ならば根 – はじめは全部の頂点が根 int par[MAX_N]; // 親の番号 // n 要素で初期化 void init(int n) { for (int i = 0; i < n; i++) par[i] = i; }
15.
// 木の根を求める int root(int
x) { if (par[x] == x) { // 根 return x; } else { return par[x] = root(par[x]); // 経路圧縮 } } // x と y が同じ集合に属するか否か bool same(int x, int y) { return root(x) == root(y); } Union-Find 木の実装(ランク無し)
16.
// x と
y の属する集合を併合 void unite(int x, int y) { x = root(x); y = root(y); if (x == y) return; par[x] = y; } Union-Find 木の実装(ランク無し)
17.
Union-Find 木の実装(ランク有り) int par[MAX_N],
rank[MAX_N]; void init(int n) { for (int i = 0; i < n; i++) { par[i] = i; rank[i] = 0; } } int root(int x) { return par[x] == x ? x : par[x] = root(par[x]); } bool same(int x, int y) { return root(x) == root(y); } void unite(int x, int y) { x = root(x); y = root(y); if (x == y) return; if (rank[x] < rank[y]) { par[x] = y; } else { par[y] = x; if (rank[x] == rank[y]) rank[x]++; } }
18.
補足 ? Union-Find 木はグループをまとめることはでき ても,分割することはできない 重要な制約 ?
Union-Find 木を改造して機能を付加することが 必要になるような問題もあります
Download