【问题描述】给定一个有向网,每个结点代表一个城市,边上的权值表示两个端点城市之间的距离,求给定的任意两个城市之间的最短路径。如果存在输出路径和路径距离,如果两个城市不可达则输出0.
【输入形式】
7 8 //结点数(结点编号从1开始连续编码),边的数量 1 2 4 //每个活动的起点和终点,活动完成所需时间 1 3 3 2 4 5 3 4 3 4 5 1 4 6 6 5 7 5 6 7 2 1 6 //起点和终点
【输出形式】
如果存在路径则输出最短路径和路径值:
1 3 4 6
12
如果不存在则输出:
0
#include <stdio.h>
#include <stdbool.h>
#define MAX_NODES 100 // 最大结点数
int graph[MAX_NODES][MAX_NODES]; // 邻接矩阵表示有向网
int dist[MAX_NODES]; // 存储起点到每个结点的最短距离
int path[MAX_NODES]; // 存储最短路径
// 初始化有向网
void initializeGraph(int numNodes) {
for (int i = 1; i <= numNodes; i++) {
for (int j = 1; j <= numNodes; j++) {
graph[i][j] = -1; // 初始设置为不可达,-1 表示无穷大
}
}
}
// 添加有向边
void addEdge(int startNode, int endNode, int distance) {
graph[startNode][endNode] = distance;
}
// Dijkstra 算法求解最短路径
bool dijkstra(int startNode, int endNode, int numNodes) {
bool visited[MAX_NODES];
for (int i = 1; i <= numNodes; i++) {
dist[i] = graph[startNode][i]; // 初始化起点到其他结点的距离
visited[i] = false; // 标记所有结点未访问过
if (i != startNode && dist[i] != -1) {
path[i] = startNode; // 记录最短路径的前驱结点
} else {
path[i] = -1; // -1 表示没有前驱结点
}
}
dist[startNode] = 0; // 起点到自身的距离为0
visited[startNode] = true; // 标记起点已访问
for (int i = 2; i <= numNodes; i++) {
int minDist = -1;
int minNode;
// 找出当前未访问结点中距离起点最近的结点
for (int j = 1; j <= numNodes; j++) {
if (!visited[j] && dist[j] != -1 && (minDist == -1 || dist[j] < minDist)) {
minDist = dist[j];
minNode = j;
}
}
if (minDist == -1) {
break; // 所有结点都不可达,退出循环
}
visited[minNode] = true; // 标记该结点已访问
// 更新其他未访问结点的最短距离
for (int j = 1; j <= numNodes; j++) {
if (!visited[j] && graph[minNode][j] != -1) {
int newDist = dist[minNode] + graph[minNode][j];
if (dist[j] == -1 || newDist < dist[j]) {
dist[j] = newDist;
path[j] = minNode;
}
}
}
}
return (dist[endNode] != -1); // 返回是否存在最短路径
}
// 输出最短路径和路径值
void printShortestPath(int startNode, int endNode) {
int shortestPath[MAX_NODES];
int numNodes = 0;
// 根据最短路径的前驱结点逆序构造最短路径
int currentNode = endNode;
while (currentNode != startNode) {
shortestPath[numNodes++] = currentNode;
currentNode = path[currentNode];
}
shortestPath[numNodes++] = startNode;
// 输出最短路径(逆序)
for (int i = numNodes - 1; i >= 0; i--) {
printf("%d ", shortestPath[i]);
}
printf("\n");
printf("%d\n", dist[endNode]); // 输出路径值
}
int main() {
int numNodes, numEdges;
scanf("%d %d", &numNodes, &numEdges); // 输入结点数和边数
initializeGraph(numNodes);
for (int i = 0; i < numEdges; i++) {
int startNode, endNode, distance;
scanf("%d %d %d", &startNode, &endNode, &distance); // 输入每条边的起点、终点和距离
addEdge(startNode, endNode, distance); // 添加有向边
}
int startNode, endNode;
scanf("%d %d", &startNode, &endNode); // 输入起点和终点
if (dijkstra(startNode, endNode, numNodes)) {
printShortestPath(startNode, endNode); // 输出最短路径和路径值
} else {
printf("0\n"); // 不存在最短路径,输出0
}
return 0;
}
算法
这段代码使用了 Dijkstra 算法来解决最短路径问题。Dijkstra 算法是一种利用贪心策略解决单源最短路径问题的算法。它通过不断更新起点到各个结点的最短距离来找到最短路径。在每一步中,选择当前未访问的结点中距离起点最近的结点,并更新其他未访问结点的最短距离,直到找到起点到终点的最短路径或所有可达结点都被访问为止。