素集合(Disjoint set)
# 目次
# Class
要素の重複のない複数の集合を管理するDisjoint Setというデータ構造.
- コンストラクタに要素の数を渡して初期化する.初期状態ではすべての要素がそれぞれの集合をなす。
same
で2つの要素が同じ集合に属するかどうかを判定する.unite
で2つの要素が含まれる集合を統合する.
class DisjointSet {
public:
DisjointSet(int n) {
rank.resize(n);
parent.resize(n);
for (int i=0; i<n; i++) rank[i] = 0, parent[i] = i;
}
bool same(int x, int y) {
return root(x) == root(y);
}
void unite(int x, int y) {
x = root(x), y = root(y);
if (rank[x] > rank[y]) {
parent[y] = x;
} else {
parent[x] = y;
if (rank[x] == rank[y]) rank[y]++;
}
}
private:
vector<int> rank;
vector<int> parent;
int root(int x) {
if (x != parent[x]) {
parent[x] = root(parent[x]);
}
return parent[x];
}
};
# Usage
無効グラフに閉路が含まれるかを判定する.
struct Edge { int src, dst; };
bool hasCycle(vector<Edge> &edges, int n) {
DisjointSet ds(n);
for (auto edge: edges) {
if (ds.same(edge.src, edge.dst)) {
return true;
}
ds.unite(edge.src, edge.dst);
}
return false;
}
int main(void) {
vector<Edge> edges;
edges.push_back({ 0, 1 });
edges.push_back({ 1, 2 });
edges.push_back({ 2, 0 });
if (hasCycle(edges, 3)) cout << "yes";
else cout << "no";
cout << endl;
}