アルゴリズム1ユニオン検索セット

アルゴリズム1ユニオン検索セット

互いに素-セットは:すなわち、含む合并集合查找集合中的元素二つの動作のツリーデータ構造は、の言葉は、すでにその機能をカバーしました。多くの場合、使用中の森林によって表されます。

1.アイデアを収集して収集する

1.1アルゴリズムのアイデア

セット内の要素がツリー上の異なるノードと見なされる場合、2つの要素が同じセットに属しているかどうかを判断する問題は、それらが配置されているツリーのルートが同じルートであるかどうかの問題になります。

1.2パス圧縮

同じツリーにはさまざまなブランチがあり、ブランチにはさまざまなレベルのリーフノード(つまり、要素と呼ばれるもの)があります。特定のリーフノードのルートノードを見つける速度をチェックするために、要素xからルートノードルートまでのすべてのリーフノードの親が検索時にルートノードとして設定されます。この最適化の方法は、パス圧縮と呼ばれます

パス圧縮の最適化後、平均の複雑さはアッカーマン関数の逆関数と見なすことができます。これは、実際のアプリケーションでは大まかに定数と見なすことができます。

1.3問題の説明

親戚を例にとると、友人があなたの親戚であることを知らないかもしれません。彼はあなたの曽祖父の祖父の義理の息子のいとこの姪の孫かもしれません。

家族地図から、2人が親戚かどうかを簡単に判断できます。しかし、2人の最も近い共通の祖先が数世代離れており、家族が非常に大きくなると、2人の親戚をテストすることが非常に困難になります。結婚とベンが親戚であるかどうかを伝えるプログラムを作成します。

説明:これは、ユニオン検索の非常に古典的な例です。コレクションのアイデアを使用して、各人のコレクションを作成します。最初は、コレクション要素は本人です。つまり、最初は、誰も彼の親戚であることがわかりません。将来的には、親戚が与えられるたびに、セットのマージが開始されます。このようにして、現在の状態での収集関係がリアルタイムで取得されます。

そして収集する

1.4主な操作

複合検索の主な操作は、初期1回、マージ2回、検索3回、判断4回です。

  • セットの初期化と検索(InitUnionFind)
  • 2つの互いに素なセット(Union)
    2つの要素をマージし、それぞれのルートノードを見つけてから、一方の要素のルートノードの親をもう一方の要素のルートノードにポイントします。
  • 要素のルートを検索(検索)
    ルート要素を検索しますparent--->parent--->parent.....要素のルートノードを見つける方法に多くの要素がある場合、パス圧縮最適化アルゴリズムが使用されます。要素の親をルートノードまたは祖先に転送します。
  • 2つの要素が同じセットに属しているかどうかを判断します(isConnected)
    2つの要素が同じセットに属しているかどうかを判断します。つまり、それぞれのルートノードを見つけてから、2つのルートノードが等しいかどうかを判断します。

2つ、例を見つける

2.1スムーズなプロジェクト

制限時間:4000/2000 MS(Java /その他)メモリ制限:65536/32768 K(Java /その他)
合計提出数:70879承認された提出物:37912

問題の説明
州は、都市の交通状況を調査し、既存の都市道路の統計表を取得します。この表には、各道路に直接接続されている市と町がリストされています。州政府の「ブロックされていないプロジェクト」の目標は、州内の任意の2つの町の間の交通を可能にすることです(ただし、道路を介して間接的に到達可能である限り、必ずしも道路で直接接続されている必要はありません)。少なくともいくつの道路を建設する必要があるか尋ねてください。

入力
テスト入力には、いくつかのテストケースが含まれています。各テストケースの最初の行は、町の数N(<1000)と道路の数Mの2つの正の整数を示します。後続のM行はMの道路に対応し、各行はそれぞれ正の整数のペアを示します。道路で直結している2つの町の数。簡単にするために、町には1からNまでの番号が付けられています。
注:2つの都市間に複数の道路が存在する可能性があるため、
3 3
1 2
1 2
2 1の入力
も有効です
。Nが0の場合、入力は終了し、ユースケースは処理されません。

出力
テストケースごとに、1行に建設する必要のある道路の最小数を出力します。

サンプル入力

4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
1 2
3 5
999 0
0

サンプル出力

1
0
2
998

ヒント
ヒント

巨大な入力、scanfをお勧めします。

出典
浙江大学コンピューター大学院再審査コンピューター試験-2005


JGShiningをお勧めします

#include<iostream>
#include<stdio.h>
using namespace std;

int pre[1010];

int unionSearch(int root)
{

    int son,tmp;
    son = root;
    /*查找根节点*/
    while(root!= pre[root])
        root = pre[root];
    /*路径压缩*/
    while(son!= root)
    {
        tmp = pre[son];
        pre[son] = root;
        son = tmp;
    }

    return root; // 返回跟界定啊
}

int main()
{
    int num, road, total,start, end, root1, root2;
    while(scanf("%d", &num) && num && scanf("%d", &road))
    {
        total = num-1;// num-1 个集合(元素);
        for(int i=1; i<=num; i++)
        {
            pre[i] = i; //1.初始化并查集,此时每个元素自己都是根节点
        }

        while(road--)
        {
            scanf("%d%d", &start, &end); //2.不同集合根据路径,开始合并
            root1 = unionSearch(start); //3.查找根节点,路径压缩
            root2 = unionSearch(end);
            if(root1 !=root2)  //4.判断,根节点不一样
            {
                pre[root1] = root2; //选出一个当根节点
                total--; //集合少一个,关系少一个
            }
        }
        cout<<total<<endl; //计算剩余的集合
    }
    return 0;
}

【おすすめ】

おすすめ

転載: blog.csdn.net/qq_36148847/article/details/83759652