C++におけるUnion-Findデータ構造の実装と活用方法


Union-Findデータ構造の基本的な実装は、要素を木構造で表現し、各要素が所属する集合を示す親ノードを持つことです。以下に、C++でのUnion-Findデータ構造の実装例を示します。

#include <vector>
class UnionFind {
private:
    std::vector<int> parent;
    std::vector<int> rank;
public:
    UnionFind(int n) {
        parent.resize(n);
        rank.resize(n, 0);
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
    }
    int find(int x) {
        if (parent[x] != x) {
            parent[x] = find(parent[x]);
        }
        return parent[x];
    }
    void unite(int x, int y) {
        int rootX = find(x);
        int rootY = find(y);
        if (rootX != rootY) {
            if (rank[rootX] < rank[rootY]) {
                parent[rootX] = rootY;
            } else if (rank[rootX] > rank[rootY]) {
                parent[rootY] = rootX;
            } else {
                parent[rootY] = rootX;
                rank[rootX]++;
            }
        }
    }
};

上記の実装では、parentベクターは各要素の親ノードを保持し、rankベクターは各要素のランク(木の高さの上限)を保持しています。find関数は要素の所属する集合を見つけるために再帰的に親ノードを辿り、unite関数は2つの集合をマージします。

Union-Findデータ構造は、以下のようなさまざまな問題に利用することができます。

  1. 連結成分の管理: グラフの連結成分を管理するために使用します。例えば、与えられたグラフが連結かどうかを判定することや、連結成分の個数を数えることができます。

  2. サイクルの検出: グラフにサイクルが存在するかどうかを判定するために使用します。Union-Findを使って辺の追加時にサイクルができないように制約を課すことができます。

  3. 最小全域木 (Minimum Spanning Tree) の構築: Kruskalのアルゴリズムなどを用いて、最小全域木を構築するために使用します。

  4. クラスタリング: クラスタリングアルゴリズムにおいて、Union-Findを使って類似した要素をグループ化することができます。

このように、Union-Findデータ構造は様々な応用があります。上記の実装例を参考にしながら、具体的な問題に対して適切な方法でUnion-Findを活用してみてください。