Prim&Kruskal C語言代碼

這是中科大2020年春《算法分析與設計》的課程實驗3。

實驗題目

題目
助教給出補充,所給樹的節點一定是20,也就是說默認輸入輸出都是一個20*20的矩陣。
我已經在GitHub上傳我的代碼和測試樣例,這是鏈接。
https://github.com/Xixo99/exp3_Prim-Kruskal
具體算法原理我就不解釋了,因爲我覺得我表達能力肯定沒有那些寫書的人好哈哈。

代碼

/*******************
 * 描述:最小生成樹 
 * 		 分別用Prim算法和Kruskal算法實現 
 * 		 輸入是一個20*20的矩陣,以txt的格式讀入
 *       輸出是一個20*20的矩陣,以txt的格式輸出 
 *時間:2020/5/11 
 *******************/

#include<stdio.h>
#include<stdlib.h>

const int Size = 20;	//節點的個數,這裏給定了是20
const int INF = 2147483647;		//此爲int可表示整數範圍內的最大正數
int G[Size][Size],Ans[Size][Size],B[Size][Size];	//G爲全連接圖中的邊權重,對角線均爲0,Ans矩陣爲答案矩陣,B矩陣在Kruskal算法中有應用

//Node 和 count 的含義在兩種算法中不同,請注意區分
int Node[Size];	
int count;

//用於在Prim算法中
//判斷函數節點是否已經加入“被連接的節點”
bool NotInNode(int j) {
	for (int i=0;i <= count;i++){
		if (j == Node[i]) {
			return false;
		}
	}
	return true;
} 
 
void Prim(){
	//在本算法中,Node數組用於記錄已被加入連接的節點
	int start,end;
	int node;
	
	for (int i=1; i< Size ; i++) {
		Node[i] = -1;
	}
	Node[0] = 0	;	//第一個引入的節點是0 
	
	int min = INF; 
	for(count = 0; count < Size - 1 ; count++) { 	//總共要新增Size-1條邊 
		for (int i = 0;i <= count; i++) {	//找出count+1個已經在樹裏的節點,遍歷他們的所有連向其他節點的邊
			node =  Node[i]; 
			for(int j =0; j < Size ; j++) {	//遍歷一個節點的所有邊 
				if (j != node && NotInNode(j)) {
					if (G[node][j] < min) {
						min = G[node][j];
						start = node; 
						end = j; 
					} 
				}  
			}  
		} 
		//將最小值的結果保存在Ans數組中
		Ans[start][end] = 1; 
		Ans[end][start] = 1;
		min = INF;
		Node[count+1] = end;
		start = -1;
		end = -1;
	}
	return ; 
}

bool  visit(int i) {
	Node[i] = 0; 	//表示節點未訪問完成 
	for (int j = 0;j<Size;j++) {
		if (B[i][j] == 1) {
			if (Node[j] == 0) return true;	//訪問一個未訪問完成的節點說明存在迴路 
			B[i][j] = 0;
			B[j][i] = 0;
			if (visit(j)) return true;
		}
	}
	Node[i] = 1;	//表示節點已經訪問完畢 
	return false;
}

bool IsRoop() {	//判斷圖中是否存在環 
	//初始Node[i]均爲-1 
	for (int i=0;i<Size;i++) {
		Node[i] = -1;
	}
	for (int i=0;i<Size-1;i++) {
		if(Node[i] == -1) {
			if (visit(i)) return true;	//訪問i時發現環路 
		}
	}
	return false;	//未發現環路 
}

void Kruskal(){
	int last_min,start,end;
	for (count = 0; count < Size -1; count++){	//增加Size-1條邊 
		int min = INF;	//初始化最小值
		for(int i = 0; i < Size-1;i++) {
			for (int j = i + 1; j < Size; j++) {
				if (G[i][j] < min && G[i][j] >= last_min) {
					for (int t1=0;t1 < Size;t1++) {
						for (int t2=0;t2 < Size;t2++) {
							B[t1][t2] = Ans[t1][t2];
						}
					}
					B[i][j] = 1;
					B[j][i] = 1;
					if(!IsRoop()) {	//沒有環路就更新最小值 
						min = G[i][j];
						start = i;
						end = j;
					} 
				}
			}
		} 
		
		//更新Ans數組,保存答案
		Ans[start][end]=1;
		Ans[end][start]=1; 
		last_min = min;
		G[start][end] = INF;
		G[end][start] = INF;
	}
}
 
int main(void){
	FILE *pr = NULL,*pw = NULL; 

	//讀入test.txt,寫在output.txt
	pr = fopen("test.txt", "r");
	if (pr == NULL ) {
		printf("Can't open 'test.txt'!\n");
		return 1; 
	}
	pw = fopen("output.txt","w");
	if (pw == NULL) {
		printf("Can't open 'output.txt'!\n"); 
		return 2; 
	}
	
	//更新權重,順便將Ans數組初始化
	for(int i = 0; i < Size; i++) {
		for (int j = 0; j < Size; j++) {
			Ans[i][j] = 0;  
			fscanf(pr,"%d",&G[i][j]);  
		}
	}
	
	//兩種方案均可選,臨時註釋掉不需要用的另外一種就可以了
	Prim();
//	Kruskal();
	
	//輸出數組
	for(int i = 0; i < Size; i++) {
		for(int j = 0 ; j <= i; j++ ) {
			fprintf(pw,"%d\t",Ans[i][j]); 
			printf("%d ",Ans[i][j]);
		}
		fprintf(pw,"\n");
		printf("\n");
	}
	return 0;
}


感謝大家的支持和點贊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章