モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

目次目次を開く/閉じる

Union-Find サンプル

モーダルを閉じる

ステッカーを選択してください

お支払い手続きへ
モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2016/07/10
最終更新最終更新
2018/10/15
記事区分記事区分
一般公開

目次

    業務ではデータベース設計とSQL最適化を担当

    プログラミングコンテストでのデータ構造』で紹介されている Union-Find 木で集合を表現すると、以下のクエリを高速に実行できます。集合一つが一つの木となるため、複数の集合がある場合は全体として森になります。

    • ある要素 a_ia_j が同じ集合に属しているかどうかの判定
    • 二つの集合を一つの集合にまとめる

    サンプル

    POJ 1182

    #include <iostream>
    #include <cstdio>
    using namespace std;
    
    const int MAXN = 101024;
    
    // Union Find >>>>>>>>>>>>>
    
    int par[MAXN * 3]; // ノード i の属する Union Find 木におけるノード i の親
    int rnk[MAXN * 3]; // ノード i の属する Union Find 木の深さ
    
    void init(int n) { // 森の初期化 (ノード数 1 の木の集合)
        for(int i = 0; i < n; ++i) {
            par[i] = i; // ノード i のみからなる木
            rnk[i] = 0; // 深さ 0
        }
    }
    
    int find(int x) { // ノード i の属する Union Find 木の root
        if(par[x] == x) return x;
        else return par[x] = find(par[x]); // root を return しつつ、次回 find の高速化のためにノード x を直接 root につなぐ
    }
    
    bool same(int x, int y) { // クエリ1 (判定)
        return find(x) == find(y);
    }
    
    void unite(int x, int y) { // クエリ2 (二つの木をまとめる)
        x = find(x);
        y = find(y);
        if(x == y) return;
        if(rnk[x] < rnk[y]) { // root が x の木の方が root が y の木よりも低い
            par[x] = y; // root y に x の木をつなぐ
        }
        else {
            par[y] = x; // root x に y の木をつなぐ
            if(rnk[x] == rnk[y]) ++rnk[x]; // 同じ高さだったならばまとめたことによって高さ +1
        }
    }
    
    // <<<<<<<<<<<<<<< Union Find
    
    int N,K;
    int type[MAXN];
    int X[MAXN];
    int Y[MAXN];
    
    int main() {
        cin>>N>>K;
        for(int i = 0; i < K; ++i) scanf("%d %d %d", &type[i], &X[i], &Y[i]); // POJ cin 遅い問題対応
        for(int i = 0; i < K; ++i) {--X[i]; --Y[i];}
    
        init(N*3); // 初期化
    
        int res = 0;
        for(int i = 0; i < K; ++i) {
            int x = X[i], y = Y[i];
            if(x < 0 || y < 0 || N <= x || N <= y) {
                ++res;
                continue;
            }
            if(type[i] == 1) {
                if(same(x, y + N) || same(x, y + 2*N)) ++res;
                else for(int i = 0; i < 3; ++i) unite(x + i*N, y + i*N); // i が A/B/C に属すこと <=同値=> j が A/B/C に属すこと
            }
            else {
                if(same(x, y) || same(x, y + 2*N)) ++res;
                else {
                    unite(x, y + N); // i が A/B/C に属すこと <=同値=> j が B/C/A に属すこと
                    unite(x + N, y + 2*N);
                    unite(x + 2*N, y);
                }
            }
        }
        cout << res << endl;
        return 0;
    }
    
    Likeボタン(off)0
    詳細設定を開く/閉じる
    アカウント プロフィール画像

    業務ではデータベース設計とSQL最適化を担当

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    >>さらに詳しくステッカーを贈る
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      ログインする

      関連記事