通过Dijkstra算法,求两点间最短路径及长度。
输入样例说明:
3 3//第一组输入的顶点数和边数
A B C//三个顶点
A B 1//从A到B有权值为1的边,以此类推
B C 1
A C 3
A C//求A到C的最短路径
···//其余输入
0 0//输入结束
输入样例:
3 3
A B C
A B 1
B C 1
A C 3
A C
6 8
A B C D E F
A F 100
A E 30
A C 10
B C 5
C D 50
E D 20
E F 60
D F 10
A F
5 6
A B C D E
A B 5
A E 50
B E 10
A D 10
D C 10
E C 10
A C
0 0
输出样例:
2
A B C
60
A E D F
20
A D C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MaxVertexNum 10
#define MaxInt 999
typedef struct MGraph{
char vex[MaxVertexNum];
int edge[MaxVertexNum][MaxVertexNum];
int vexNum, edgeNum;
} MGraph;/*ˈmeɪtrɪks*/
void GraphInit(MGraph *G);
void GraphShow(MGraph G);
void addEdge(MGraph *G, char src, char des, int weight);
int Dijkstra(MGraph G, int srcPos, int desPos, char *path);
int main() {
MGraph G;
while (scanf("%d %d%*c", &G.vexNum, &G.edgeNum) && G.vexNum != 0) {
char src, des;//源点和目标点
int srcPos, desPos;//源点和目标点的位序
int weight;//边的权值
char path[MaxVertexNum] = "";//最短路径
/*构造无向图*/
GraphInit(&G);
for (int i = 0; i < G.vexNum; i++) scanf("%c%*c", G.vex + i);
for (int i = 0; i < G.edgeNum; i++) {
scanf("%c %c %d%*c", &src, &des, &weight);
addEdge(&G, src, des, weight);
}
/*Dijkstra求最短路径*/
scanf("%c %c%*c", &src, &des);
for (int i = 0; i < G.vexNum; i++) {
/*将源目结点转化为对应位序*/
if (G.vex[i] == src) srcPos = i;
if (G.vex[i] == des) desPos = i;
}
printf("%d\n", Dijkstra(G, srcPos, desPos, path));
for (int i = strlen(path) - 1; i >= 0; i--) {
printf("%c%c", path[i], !i ? 10 : 32);//反向输出
}
}
return 0;
}
int Dijkstra(MGraph G, int srcPos, int desPos, char *path) {
int dist[MaxVertexNum];//每个结点与源点的最短路径长度,记为dist
int final[MaxVertexNum];//标记每个结点是否已经访问,已访问的结点记为集合S
int lastAlter[MaxVertexNum];//最后一次修改当前结点dist值的结点的下标,用于回溯路径
/*初始化*/
for (int i = 0; i < G.vexNum; i++) {
lastAlter[i] = srcPos;//从目标结点回溯到源点的路径恰好为path,所以回溯结束的标志就是访问到了源点
dist[i] = G.edge[srcPos][i];//初始值就是源点到各个结点的弧的长度
final[i] = 0;//初始时每个结点都没访问
}
final[srcPos] = 1;//源点默认已经被访问
/*主循环*/
for (int i = 0; i < G.vexNum; i++) {
int minDis = MaxInt;//最短路径长度
int minPos = -1;//最短路径对应结点
/*选出一个不在集合S中且距离源点最近的结点*/
for (int j = 0; j < G.vexNum; j++) {
if (!final[j]) {
if (dist[j] < minDis) {
/*更新最短路径长度和对应结点*/
minDis = dist[j];
minPos = j;
}
}
}
final[minPos] = 1;//将当前最短路径对应的结点加入集合S
if (minPos == desPos) break;//已经把目标结点加入了集合S
/*更新最短路径和距离*/
for (int j = 0; j < G.vexNum; j++) {
//如果当前结点不在S中,且加入了新结点后当前结点与源点的距离减小,更新距离
if (!final[j] && minDis + G.edge[minPos][j] < dist[j]) {
dist[j] = minDis + G.edge[minPos][j];//更新距离
lastAlter[j] = minPos;//G.vex[minPos]结点修改了G.vex[j]结点的dist值
}
}
}
/*通过lastAlter回溯得到路径path*/
int node = desPos, i = 0;
while (node != srcPos) {
path[i++] = G.vex[node];
node = lastAlter[node];
}
path[i] = G.vex[srcPos];
return dist[desPos];
}
void GraphInit(MGraph *G) {
for (int i = 0; i < G->vexNum; i++) {
for (int j = 0; j < G->vexNum; j++) {
G->edge[i][j] = MaxInt;
}
}
}
void GraphShow(MGraph G) {
printf(" ");
for (int i = 0; i < G.vexNum; i++) {
printf("%3c%c", G.vex[i], i == G.vexNum - 1 ? 10 : 32);
}
for (int i = 0; i < G.vexNum; i++) {
printf("%c ", G.vex[i]);
for (int j = 0; j < G.vexNum; j++) {
if (G.edge[i][j] == MaxInt) {
printf("%3c%c", 'x', j == G.vexNum - 1 ? 10 : 32);
} else {
printf("%3d%c", G.edge[i][j], j == G.vexNum - 1 ? 10 : 32);
}
}
}
}
void addEdge(MGraph *G, char src, char des, int weight) {
int i = 0, j = 0;
while (G->vex[i] != src) i++;
while (G->vex[j] != des) j++;
G->edge[i][j] = G->edge[j][i] = weight;
}