187 lines
4.3 KiB
C++
187 lines
4.3 KiB
C++
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
|
|
#define MAX_V 100 /*最大節點數*/
|
|
#define Infinite 1073741823
|
|
|
|
long int dist[MAX_V+1][MAX_V+1];
|
|
int path[MAX_V+1][MAX_V+1]; // 追蹤路徑的矩陣
|
|
int N; // 節點數量
|
|
int source, sink; // 起點和終點
|
|
|
|
void init();
|
|
bool floydWarshall();
|
|
void output_path();
|
|
void output_step();
|
|
void print_path(int start, int end);
|
|
|
|
int main() {
|
|
init();
|
|
|
|
// 檢查是否存在負權迴路
|
|
if (floydWarshall()) {
|
|
printf("\n警告:圖形中存在負權迴路,計算結果可能不正確!\n");
|
|
output_path();
|
|
} else {
|
|
output_path();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void init(){
|
|
FILE *fptr;
|
|
int i, j, weight,line_count=0;
|
|
char line[256];
|
|
|
|
fptr = fopen("shortestPath_up_1.dat", "r");
|
|
if (fptr == NULL) {
|
|
perror("shortestPath_up_1.dat");
|
|
exit(1);
|
|
}
|
|
|
|
// 計算總頂點數
|
|
while (fgets(line, sizeof(line), fptr)) {
|
|
line_count++;
|
|
}
|
|
N = line_count;
|
|
rewind(fptr);
|
|
|
|
// 初始化距離矩陣與路徑矩陣
|
|
for (i = 1; i <= N; i++) {
|
|
for (j = 1; j <= N; j++) {
|
|
if (i == j) {
|
|
dist[i][j] = 0;
|
|
path[i][j] = i;
|
|
} else {
|
|
dist[i][j] = Infinite;
|
|
path[i][j] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 讀取上三角矩陣
|
|
for (i = 1; i <= N; i++) {
|
|
for (j = i; j <= N; j++) {
|
|
if (fscanf(fptr, "%d", &weight) == 1) {
|
|
if (weight != 0) { // 只處理非零權重
|
|
dist[i][j] = weight;
|
|
path[i][j] = i;
|
|
// 因為是無向圖,所以對稱位置也要設定
|
|
if (i != j) {
|
|
dist[j][i] = weight;
|
|
path[j][i] = j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// 跳過該行剩餘的字符
|
|
fgets(line, sizeof(line), fptr);
|
|
}
|
|
|
|
fclose(fptr);
|
|
printf("檔案內權重如下\n");
|
|
output_step();
|
|
|
|
printf("\n輸入起始節點 (1~%d): ", N);
|
|
scanf("%d", &source);
|
|
printf("輸入目標節點 (1~%d): ", N);
|
|
scanf("%d", &sink);
|
|
}
|
|
|
|
bool floydWarshall(){
|
|
int k, i, j;
|
|
bool has_negative_cycle = false;
|
|
long int temp_dist[MAX_V+1][MAX_V+1];
|
|
|
|
// 主要的 Floyd-Warshall 演算法
|
|
for (k = 1; k <= N; k++) {
|
|
for (i = 1; i <= N; i++) {
|
|
for (j = 1; j <= N; j++) {
|
|
if (dist[i][k] != Infinite &&
|
|
dist[k][j] != Infinite &&
|
|
dist[i][k] + dist[k][j] < dist[i][j]) {
|
|
dist[i][j] = dist[i][k] + dist[k][j];
|
|
path[i][j] = path[k][j];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 複製目前的距離矩陣
|
|
for (i = 1; i <= N; i++) {
|
|
for (j = 1; j <= N; j++) {
|
|
temp_dist[i][j] = dist[i][j];
|
|
}
|
|
}
|
|
|
|
// 再執行一次迭代來檢查負權迴路
|
|
for (k = 1; k <= N; k++) {
|
|
for (i = 1; i <= N; i++) {
|
|
for (j = 1; j <= N; j++) {
|
|
if (dist[i][k] != Infinite &&
|
|
dist[k][j] != Infinite &&
|
|
dist[i][k] + dist[k][j] < temp_dist[i][j]) {
|
|
has_negative_cycle = true;
|
|
goto end_check; // 找到負權迴路後直接跳出
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
end_check:
|
|
return has_negative_cycle;
|
|
}
|
|
|
|
void print_path(int start, int end) {
|
|
if (start == end) {
|
|
printf("頂點%d", start);
|
|
return;
|
|
}
|
|
if (path[start][end] == -1) {
|
|
printf("無路徑");
|
|
return;
|
|
}
|
|
print_path(start, path[start][end]);
|
|
printf(" → %d", end);
|
|
}
|
|
|
|
void output_step(){
|
|
int i, j;
|
|
|
|
printf("\t");
|
|
for (j = 1; j <= N; j++) {
|
|
printf("V%d\t", j);
|
|
}
|
|
printf("\n");
|
|
|
|
for (i = 1; i <= N; i++) {
|
|
printf("V%d\t", i);
|
|
for (j = 1; j <= N; j++) {
|
|
if (dist[i][j] == Infinite)
|
|
printf("∞\t");
|
|
else
|
|
printf("%2ld\t", dist[i][j]);
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
void output_path(){
|
|
int i, j;
|
|
|
|
printf("\n節點間最短距離矩陣:\n");
|
|
output_step();
|
|
|
|
if (dist[source][sink] == Infinite) {
|
|
printf("\n節點 V%d 到節點 V%d 沒有路徑\n", source, sink);
|
|
} else {
|
|
printf("\n從節點 V%d 到節點 V%d 的最短距離為:%ld\n",
|
|
source, sink, dist[source][sink]);
|
|
printf("最短路徑:");
|
|
print_path(source, sink);
|
|
printf("\n");
|
|
}
|
|
}
|