最小生成樹(克魯斯卡爾演算法)資料結構

菜鴨。發表於2020-12-14

思路

  1. 雙親表示法
    用雙親表示法表示單個集合,其中雙親作為標記,在同一個連通分量裡的點雙親相同(需要在開始就將雙親設定,後面會與權值比較,所以越大越好,但開始都不相同)
  2. 三元組
    三元組表示要輸入的形式
  3. 迭代找最小權值
    在找到權值並使用後,將其變成負數,最後輸出時要變回來

問題描述:

見習題集P152。用克魯斯卡爾(Kruskal)演算法求無向網的最小生成樹。

輸入:
輸入資料第一行為兩個正整數n(1<n<=30)和m(1<m<100),分別表示頂點數和邊數。後面緊跟m行資料,每行資料是一條邊的資訊,包括三個數字,分別表示該邊的兩個頂點和邊上的權值。
輸出:
按順序輸出Kruskal演算法求得的最小生成樹的邊集,每行一條邊,包括三個數字,分別是該邊的兩個頂點和邊上的權值,其中第一個頂點的編號應小於第二個頂點的編號。
示例輸入
8 11
1 2 3
1 4 5
1 6 18
2 4 7
2 5 6
3 5 10
3 8 20
4 6 15
4 7 11
5 7 8
5 8 12
示例輸出
1 2 3
1 4 5
2 5 6
5 7 8
3 5 10
5 8 12
4 6 15

#include<stdio.h>
# define max_tree_size 100

typedef struct NODE{//邊的定義 
	int parent;//雙親的位置 (如果雙親相同,就在同一個集合裡)
	//int next;//相關聯的節點位置 
	int date;//自己點的位置 
}D[100]; 
typedef struct tri{//三元組 
	int x;//前繼 
	int y;//後繼 
	int weigh;//權值 
}T[100]; 
typedef struct TREE{
	tri T[100];//邊的集合 
}Tree;

int findmin(tri T[],int m,NODE D[]){//找最小的邊
	int min=999;
	int temp;
	for(int j=0;j<m;j++){//在滿足條件的情況下,直接找最小
		if(T[j].weigh<=min&&T[j].weigh>0) {
		min=T[j].weigh;
		temp=j;
		}
	} 
	if(D[T[temp].x ].parent ==D[T[temp].y ].parent )	{
		T[temp].weigh =999999;
		findmin(T,m,D);
	}//相等說明已經在一個集合了,該路徑不能走,直接999999,再也走不通 
	else {
		if(D[T[temp].x ].parent<D[T[temp].y ].parent){//因為權值總是從小到大被發現,可作為雙親 ,
		//前提是最開始的雙親都大於最小的權值 
			if(D[T[temp].x ].parent>T[temp].weigh){// 找出x,y的雙親最小的那個與當前所找到的權值比較,取較小的 
				D[T[temp].x ].parent=T[temp].weigh;//這樣能保證在同一個連通分量總能有相同的雙親 
				D[T[temp].y ].parent=T[temp].weigh;//在不同的連通分量有不同的雙親 
			}
			else D[T[temp].y ].parent=D[T[temp].x ].parent;
		} 
		else{
			if(D[T[temp].y ].parent>T[temp].weigh){
				D[T[temp].x ].parent=T[temp].weigh;
				D[T[temp].y ].parent=T[temp].weigh;
			}
			else D[T[temp].x ].parent=D[T[temp].y ].parent;
		}
		T[temp].weigh=T[temp].weigh*(-1);//為了防止下一次還找到該路徑,將權值改為負數,輸出時需要改回來 
		return temp;
	}//成功找到,將雙親設為一樣 ,在一個集合的點的雙親需要一起變 
}
int main(){
	int n,m;
	scanf("%d %d",&n,&m);
	tri T[100]; 
	NODE D[100];
	Tree p; 
	int i,j,k,count=0;
	for(i=999;i<n;i++)	D[i].parent =i;//設定一下雙親,每都不一樣 ,放到一個集合(連通分量)時就讓他們一樣 
	for(i=0;i<m;i++)	scanf("%d %d %d",&T[i].x ,&T[i].y ,&T[i].weigh );//輸入三元組
	for(i=0;i<n-1;i++){//迴圈頂點數-1次即可,就會連通 
		k=findmin(T,m,D);
		p.T[count]=T[k];//將找到的路徑存入樹中,覺得這裡有點滑稽,感覺自己騙自己,直接輸出就完了 
		count++;
		printf("%d %d %d\n",p.T[i].x ,p.T[i].y,p.T[i].weigh*(-1) ); 
	}
}

感想

樣例只過了一個,因為oj時間截止了,各位如果發現什麼錯誤,歡迎指正。
感覺自己程式碼還是很複雜,向大家請教更簡單的思路
菜雞一個的我,希望大家找我交流
期末了,要瘋狂肝資料結構的題了。

相關文章