UnionFindのテンプレコード(C++)の実装

データ構造

メソッド ~機能~

メソッド名機能
get_root_number根の番号の取得
merge二つの部分木を結合
is_same_tree同じ部分木(グループ)に属するかどうか
true:属する false:属さない
get_subtree_size「引数として与えられたノード」を含む部分木のサイズを取得
namespace template_data_structure {
    class union_find {
    public:
        /** @brief default constructor */
        union_find() = default;

        /**
         * @brief constructor 
         * @param node_count 頂点数
         */
        union_find(int node_count) : parent(std::vector<int>(node_count, root_parent_number)), subtree_size(std::vector<int>(node_count, 1)) {}
    
        /** @brief x番のノードが含まれる木の"根の番号"を取得 */
        int get_root_number(int x) {
            if (parent[x] == root_parent_number) return x;
            else return parent[x] = get_root_number(parent[x]);
        }
    
        /** @brief x, y番のノード同士を併合する */
        void merge(int x, int y) {
            int root_of_x = get_root_number(x);
            int root_of_y = get_root_number(y);
    
            if (root_of_x == root_of_y) return;
    
            if (subtree_size[root_of_x] > subtree_size[root_of_y]) merge_operation(root_of_x, root_of_y);
            else merge_operation(root_of_y, root_of_x);
        }
    
        /** 
         * @brief x, y番のノードが同じ部分木に属するか 
         * @return true:属する false:属さない
         */
        bool is_same_tree(int x, int y) {
            return get_root_number(x) == get_root_number(y);
        }
    
        /** @brief x番のノードが含まれる部分木のサイズを取得する */
        int get_subtree_size(int x) {
            return subtree_size[get_root_number(x)];
        }
        
    private:
        /** @brief 根の親を表す無効な値 */
        const int root_parent_number = -1;
        std::vector<int> parent;
        
        /** @brief subtree_size[i]:= iを根とした部分木のサイズ(iが根でない場合はアクセスされない) */
        std::vector<int> subtree_size;
    
        /**  
         * @brief 併合操作
         * より大きい方の根に、小さい方の部分木を併合する
         * 部分木サイズも更新する
         */
        std::function<void(int, int)> merge_operation = [&](int bigger_root, int smaller_root) {
            parent[smaller_root] = bigger_root;
            subtree_size[bigger_root] += subtree_size[smaller_root];
        };
    };
}

行った高速化の工夫

  • “経路圧縮
  • サイズ による合併

と、言われるやつのようです…
(以下の記事でそのように呼ばれていたので…その呼び方を使わせていただきます)

参考になった記事

Union-Find Tree を理解する!素集合系を扱うデータ構造 | アルゴリズムロジック
2つの集合が共通する要素を持たない時に「互いに素」であると言い、このような集合の集まりを「素集合系」などと言います。 素集合系の例 素集合系は、いくつかの木構造を用いることで管理...

いくつかの使用例 (C++)

いくつかの問題をC++でACしたので提出を置いておきます✨✨

Submission #59496560 - AtCoder Beginner Contest 177
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
Submission #59496472 - AtCoder Beginner Contest 378
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.
Submission #59496524 - AtCoder Regular Contest 106
AtCoder is a programming contest site for anyone from beginners to experts. We hold weekly programming contests online.

さいごに

とりあえず、必要最小限のみの実装となっています。
(まだいくつかほしい機能があるので、また追記する予定です)
AtCoderの問題でもUnionFindは結構でてくるので、よければ使ってくださいね🥰🥰

もし、「このコード使ったよ」(←励みになります)や「正しく動かないよ」ということがありましたら筆者のX(旧Twitter)まで連絡いただけると助かります。

最後までお読みいただきありがとうございましたっ
( ゚д゚)つ Bye

コメント

タイトルとURLをコピーしました