C語言實現最短路徑問題(Floyd演算法)

2020-08-09 23:53:52

本文收此文章啓發:弗洛伊德演算法

需要注意三點
①三個回圈的意義,最外層i是中轉結點,然後內層是求第j個結點通過ii結點做中轉到第k個結點的最短路徑
②路徑的儲存,注意更新的時候需要的是j->i的路徑
③一開始要給有邊的路徑設定名字

PS:如果自己有到自己的路徑 設定的輸出爲路徑的值,但課本輸出0

測試圖片:
在这里插入图片描述
檔案內容:
在這裏插入程式碼片在这里插入图片描述
輸出結果:
在这里插入图片描述
程式碼:

/*
	實現內容:Floyd演算法
	VS2019 編譯通過 王大花 2020.8.9
*/

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MaxVexNameLength 2
#define MaxPathLength 30
#define TextPath "C:\\Users\\86132\\Desktop\\最短路徑Floyd\\ALGraph.txt"

//頂點結點
typedef struct _VexNode {
	char Date[MaxVexNameLength + 1];

}VexNode;

typedef struct _Floyd {
	int** Path_Length;
	char*** Path;

}Floyd;

//圖
typedef struct _ALGraph {
	VexNode* Vertics;
	int VexNum, ArcNum;
	int** ArcMatrix;
	Floyd Flo;

}ALGraph;

//找到頂點位置
int Locate(char* ch) {
	return (3 == strlen(ch)) ? 10 * (ch[1] - '0') + ch[2] - '0' : ch[1] - '0';

}

void Creat_ALGraph(ALGraph* G) {

	FILE* fp = fopen(TextPath, "r");
	fscanf(fp, "%d%d", &G->VexNum, &G->ArcNum);

	//讀取頂點資訊 同時初始化鄰接矩陣、路徑矩陣
	G->Vertics = (VexNode*)malloc(sizeof(VexNode) * G->VexNum);
	G->ArcMatrix = (int**)malloc(sizeof(int*) * G->VexNum);
	G->Flo.Path_Length = (int**)malloc(sizeof(int*) * G->VexNum);
	G->Flo.Path = (char***)malloc(sizeof(char**) * G->VexNum);

	for (int i = 0; i < G->VexNum; i++) {
		fscanf(fp, "%s", G->Vertics[i].Date);
		//初始化鄰接矩陣 路徑矩陣
		G->ArcMatrix[i] = (int*)malloc(sizeof(int) * G->VexNum);
		G->Flo.Path_Length[i] = (int*)malloc(sizeof(int) * G->VexNum);
		G->Flo.Path[i] = (char**)malloc(sizeof(char*) * G->VexNum);

		for (int j = 0; j < G->VexNum; j++) {
			G->ArcMatrix[i][j] = INT_MAX;
			G->Flo.Path_Length[i][j] = INT_MAX;
			G->Flo.Path[i][j] = (char*)malloc(sizeof(char) * MaxPathLength);
			memset(G->Flo.Path[i][j], 0, sizeof(char) * MaxPathLength);
		}
	}

	//錄入弧的資訊
	for (int i = 0; i < G->ArcNum; i++) {
		char ch1[MaxVexNameLength + 1], ch2[MaxVexNameLength + 1];
		int tmp;
		fscanf(fp, "%s%s%d", ch1, ch2, &tmp);
		G->ArcMatrix[Locate(ch1)][Locate(ch2)] = tmp;
		G->Flo.Path_Length[Locate(ch1)][Locate(ch2)] = tmp;
	}
	for (int i = 0; i < G->VexNum; i++) {
		for (int j = 0; j < G->VexNum; j++) {
			if (INT_MAX != G->ArcMatrix[i][j]) {
				strcat(G->Flo.Path[i][j], " -> ");
				strcat(G->Flo.Path[i][j], G->Vertics[j].Date);
			}
		}
	}

	fclose(fp);
}

void Shortest_Path_Floyd(ALGraph G) {

	//只讓第i個做中轉站 計算其餘頂點之間的距離
	for (int i = 0; i < G.VexNum; i++) {
		//計算第j個頂點在第i箇中轉站的前提下和k頂點(其餘所有頂點)的距離
		for (int j = 0; j < G.VexNum; j++) {
			for (int k = 0; k < G.VexNum; k++) {

				if (INT_MAX == G.ArcMatrix[j][i] || INT_MAX == G.ArcMatrix[i][k])
					continue;
				if (INT_MAX == G.Flo.Path_Length[j][k] || G.Flo.Path_Length[j][k] > G.ArcMatrix[j][i] + G.ArcMatrix[i][k]) {
					G.Flo.Path_Length[j][k] = G.ArcMatrix[j][i] + G.ArcMatrix[i][k];

					G.Flo.Path[j][k][0] = 0;
					strcat(G.Flo.Path[j][k], G.Flo.Path[j][i]);
					strcat(G.Flo.Path[j][k], " -> ");
					strcat(G.Flo.Path[j][k], G.Vertics[k].Date);
				}
			}
		}
	}
}

void Print_Floyd_Path(ALGraph G) {

	for (int i = 0; i < G.VexNum; i++) {
		for (int j = 0; j < G.VexNum; j++) {
			if (INT_MAX != G.Flo.Path_Length[i][j])
				printf("%s%s\t路徑長度:%d\n", G.Vertics[i].Date, G.Flo.Path[i][j], G.Flo.Path_Length[i][j]);
			else
				printf("%s%s -> %s\t路徑不存在\n", G.Vertics[i].Date, G.Flo.Path[i][j], G.Vertics[j].Date);
		}
	}
}

int main() {

	ALGraph G;
	Creat_ALGraph(&G);
	Shortest_Path_Floyd(G);
	Print_Floyd_Path(G);

	return 0;
}