まず、問題のリード
そこはまだありません...より多くの都市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
三、总结
最优的选择还是加权快速合并算法