接続の問題(互いに素セット、パス圧縮)

まず、問題のリード

そこはまだありません...より多くの都市A、B、Cを伝え、そして今、政府は各都市が連通され、各都市で高速道路を構築する必要があります。私が決めたのでしかし、その後、今年の収益赤字は、予算は、あまりないが、各通信何時間2つの都市を決定するために、最後に2つの都市は、コストを節約するために、相互運用性がありません。例えば:AとCがB、ACに接続されているので、ABのストレッチ、BC間の道路は、それは、ACの時に決定されて相互に接続され、ビルドの道路には必要ありません。多くの人々は、最初にすべての後に、いくつかありますが、私は非常に難しく感じるだろう、この質問を見た隠された接続関係、独自の判断を下すためには。

第二に、ソリューション

①高速検索アルゴリズム

書式#include <stdio.hに>
 に#define N 10000

無効メイン()
{
    int型の配列[N]、X、Y、I、J、TEMP;
     // 初期化配列
    のために(私は= 0 ; I <N; I ++ 
        配列[I] = I;
     一方(scanfの(" %D%D- "、およびX&Y)== 2 ){
         // 2つの値が等しい場合は、2点の通信
        IF(配列[X] == 配列[ Y])
             続行;
         のため(アレイTEMP = [X]、J = 0 ; J <N; J ++ // すべてのポイントは、ポイント通信だけでなく、通信yにxは。ここで、両方の[X]または配列[Y]アレイに統合値であってもよいです。
            IF(配列[J] == TEMP)
                アレイ[J] = 配列[Y];
         // の必要な通信ポイント印刷 
        のprintf(" ポイントが通信のために必要:D-%D%\ N- " 、X、Y)。
    }
}

結果:

 分析:配列インデックスが異なる表す都市配列格納され、値をするために使用さを指すの通信①開始配列は、それぞれのインデックスに初期化される(すべての都市を代表して通信されなかった)②右入力ポイントを待ちます。③最初同じで格納されている点(配列インデックス)の値を決定します。同一の場合、二つの通信は、入力を待ち続け、一方で、その後、点XとYが(すなわち、統一の値を格納することができる)は、すべての通信ポイントを通信します。最後のステップを繰り返し②③

欠点: M複合操作(入力数)、N小数点命令は、番号を実行する必要がMN

②高速アルゴリズムをマージ

書式#include <stdio.hに>
 に#define N 10000

無効メイン()
{
    int型の配列[N]、X、Y、I、J;
     // 初期化配列
    のために(私は= 0 ; I <N; I ++ 
        配列[I] = I;
     一方(scanfの(" %D%D- "、およびX&Y)== 2 ){
        // 構成ツリー
        // Xのルートを見つけ、対応するインデックスの値が同じ格納された場合にのみこの点は、ツリーのルートにある場合
       ための式(I = X ;! I =配列[I]は、私は= 配列[I]);
        // ルートノードyを見つける
       ための Y = Jを(; J =配列を! [J]; J = 配列[J]);
        // ルートノードが同じで、二点通信を説明
       IF(I == J)
         続行;
        // ツリーここでX、Yツリーマージ 
       配列[I ] = J。
       printf(" 必要な通信ポイント:D-%D%\ N- " 、X、Y)。
    }
}

結果:

分析:

①グラフ全体のプロセスを表します。

1)初期:

(配列値)

0 1 2 3 4

2)入力1-2、1ツリーツリーに接続された2

0 2 2 3 4

3)ツリーの入力2-3,2ツリーに接続された3

0 2 3 3 4

4)入力1-3、1-3は、通信が操作されていないことが判明した;入力3-4、3木4にツリーを結びます 

0 1 2 3 4 4

5)入力1-4、2-4、通信にされている、動作しません

0 1 2 3 4 4

 

入力点の後に、見つけるためにルートノード点に対応する方向に応じて(2点が接続されている場合、それはルートノードが同じでなければなりません 2点が接続されているかどうかを決定するために、)。もし通信は、ノーオペレーション、一方、ツリーの最初の点マージ第2ツリーポイントへ

短所:木の層が成長引き起こし、これは主に起因していることがあり、木の前者と後者をマージすることは簡単である複合動作時間

 

③加重速いマージアルゴリズム

書式#include <stdio.hに>
 に#define N 10000

無効メイン()
{
    INT ; NUM [N]、配列[N]、X、Y、I、J
     // 初期化配列
    のための(私は= 0 ; I <N; I ++ 
        配列[I] = I。
    以下のための式(I = 0、I <Nを; I ++ 
        num[i]=1;
    while(scanf("%d-%d",&x,&y)==2){
       //构造树
       //寻找x的根节点,只有当索引和对应存储的值相同的时候,该点才是该树的根节点
       for(i=x;i!=array[i];i=array[i]);
       //寻找y的根节点
       for(j=y;j!=array[j];j=array[j]);
       //根节点为同一个,说明俩点连通
       if(i==j)
        continue;
       //合并
       //x的树大,将y合并到x上
       if(num[i]>num[j]){
        array[j]=i;
        num[i]+=num[j];
       }
       //y的树大,将x合并到y上
       else {
        array[i]=j;
        num[j]+=num[i];
       }
       printf("所需要连通的点对:%d-%d\n",x,y);
    }
}

结果:

 分析:

只需要多一个辅助记录(树的节点个数)的数组,在每次合并树的时候判断哪边的树大(小树合并到大树上,会使树的高度尽可能低),合并完后在该树的根节点加上被合并的节点数

缺点:

节点到根节点的距离可能还是过长

 

④等分路径压缩算法  

#include <stdio.h>
#define N 10000

void main()
{
    int num[N],array[N],x,y,i,j;
    //初始化数组
    for(i=0;i<N;i++)
        array[i]=i;
    for(i=0;i<N;i++)
        num[i]=1;
    while(scanf("%d-%d",&x,&y)==2){
       //构造树
       //寻找x的根节点,只有当索引和对应存储的值相同的时候,该点才是该树的根节点
       for(i=x;i!=array[i];i=array[i]);
        array[i]=array[array[i]];
       //寻找y的根节点
       for(j=y;j!=array[j];j=array[j]);
        array[j]=array[array[j]];
       //根节点为同一个,说明俩点连通
       if(i==j)
        continue;
       //合并
       //x的树大,将y合并到x上
       if(num[i]>num[j]){
        array[j]=i;
        num[i]+=num[j];
       }
       //y的树大,将x合并到y上
       else {
        array[i]=j;
        num[j]+=num[i];
       }
       printf("所需要连通的点对:%d-%d\n",x,y);
    }
}

分析:等分路径压缩其实就是在每次找点对的根节点的时候,将当前的那个节点指向他的爷爷节点,最终经过一次又一次达到节点都直接指向他们的根节点

①用图形表示整个流程:

首先有5个线性连通的点

 当使用等分路径压缩后(当前节点指向自己的爷爷节点

②用代码表示整个流程

#include <stdio.h>
#define N 10000

void main()
{
    int array[N],x,y,i,j;
    //初始化数组
    for(i=0;i<N;i++)
        array[i]=i;
    while(scanf("%d-%d",&x,&y)==2){
       //构造树
       //寻找x的根节点,只有当索引和对应存储的值相同的时候,该点才是该树的根节点
       for(i=x;i!=array[i];i=array[i])
            array[i]=array[array[i]];
       //寻找j的根节点
       for(j=y;j!=array[j];j=array[j])
            array[j]=array[array[j]];
       //根节点为同一个,说明俩点连通
       if(i==j)
        continue;
       //合并
       array[i]=array[j];
       printf("所需要连通的点对:%d-%d\n",x,y);
       for(i=0;i<10;i++){
         printf("%d ",array[i]);
       }
       printf("\n");
    }
}

结果:

 能够很明显的看出来当执行0-4时,路径进行了压缩

1 2 3 4 4  ->  2 2 4 4 4

 

三、总结

最优的选择还是加权快速合并算法

おすすめ

転載: www.cnblogs.com/g1191613819/p/12081618.html
おすすめ