【基础算法】Dijkstra算法,以上海地铁换乘为例,计算最短换乘路径和时间

一、算法概述:

该算法是一个求最短路径的算法,具体算法的思想为:

  1. 找出离源点O最近的点,把该点设为S;
  2. 以S点为中转点,查看如果以S点为中转点,计算源点O中转S点到各点的距离transfer_distance;
  3. 对比O到各点的距离对比transfer_distance,如果transfer_distance距离更短,则把O点到该点的距离调整为transfer_distance;
  4. 将S点标注为已算,计算下个点S2,重复步骤2
二、算法具体计算过程:
  1. 计算邻接矩阵 A A A A i j A_{ij} Aij为点i到点j的最短路径距离;
  2. 源点 i i i,对应邻接矩阵 A A A所在的 i i i行,为点i到其他各点的距离;
  3. 找到该行中距离 i i i最近的点 j j j,并将j列为已计算的点,下次不再计算;
  4. j j j为中转站,计算 i i i到各点的距离,如果距离小于之前已有的最短距离,则更新该点的数据;
  5. 更新完数据后,重复3,4两步;
  6. 最终得到 i i i点到其他各点的最短距离。

为了更好的理解该算法,本文打算以上海地铁中转为例,通过代码将以上的算法实现。

需要注意的是:
  1. 地铁线路之间存在换乘时间,该时间也应该计算在总路程之内;
  2. 初始化邻接矩阵的时候,计算两点间最短距离时,两点应处在同一条线路。

具体代码请前往:
https://github.com/geeklili/Dijkstra_Algorithm

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
以下是一个简单的地铁管理系统的 C 语言代码,包含了最短路径换乘的功能: ``` #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 1000 #define INF 0x3f3f3f3f int graph[MAX][MAX]; // 存储地铁线路图 int n; // 地铁站点数量 /* Dijkstra算法最短路径 参数: start: 起点 end: 终点 path[]: 存储最短路径 返回值: 最短路径长度 */ int dijkstra(int start, int end, int path[]) { int dist[MAX]; // 存储起点到各点的最短距离 int visited[MAX]; // 存储该点是否已被访问 int pre[MAX]; // 存储最短路径上的前一个点 int i, j, k, min; // 初始化 for (i = 1; i <= n; i++) { dist[i] = graph[start][i]; visited[i] = 0; // 未被访问 if (dist[i] == INF) pre[i] = -1; // 无法到达 else pre[i] = start; // 起点到该点的前一个点为起点 } dist[start] = 0; visited[start] = 1; // 计算最短路径 for (i = 2; i <= n; i++) { min = INF; for (j = 1; j <= n; j++) { if (!visited[j] && dist[j] < min) { min = dist[j]; k = j; } } visited[k] = 1; for (j = 1; j <= n; j++) { if (!visited[j] && dist[k] + graph[k][j] < dist[j]) { dist[j] = dist[k] + graph[k][j]; pre[j] = k; } } } // 构建最短路径 j = end; i = 0; while (j != start) { path[i++] = j; j = pre[j]; } path[i] = start; // 翻转路径 for (j = 0; j <= i / 2; j++) { k = path[j]; path[j] = path[i - j]; path[i - j] = k; } return dist[end]; } /* 换乘算法 参数: start: 起点 end: 终点 path[]: 存储最短路径 返回值: 最短路径长度 */ int transfer(int start, int end, int path[]) { int i, j, k, min; int dist[MAX]; // 存储起点到各点的最短距离 int visited[MAX]; // 存储该点是否已被访问 int pre[MAX]; // 存储最短路径上的前一个点 int line[MAX]; // 存储从起点到各点的最短路径所经过的线路 // 初始化 for (i = 1; i <= n; i++) { dist[i] = graph[start][i]; visited[i] = 0; // 未被访问 if (dist[i] == INF) pre[i] = -1; // 无法到达 else pre[i] = start; // 起点到该点的前一个点为起点 line[i] = -1; } dist[start] = 0; visited[start] = 1; // 计算最短路径 for (i = 2; i <= n; i++) { min = INF; for (j = 1; j <= n; j++) { if (!visited[j] && dist[j] < min) { min = dist[j]; k = j; } } visited[k] = 1; for (j = 1; j <= n; j++) { if (!visited[j] && dist[k] + graph[k][j] < dist[j]) { dist[j] = dist[k] + graph[k][j]; pre[j] = k; line[j] = graph[k][j]; // 记录经过的线路 } else if (!visited[j] && dist[k] + graph[k][j] == dist[j] && line[j] > 0) { line[j] += graph[k][j]; // 更新线路权值 } } } // 构建最短路径 j = end; i = 0; while (j != start) { path[i++] = j; j = pre[j]; } path[i] = start; // 翻转路径 for (j = 0; j <= i / 2; j++) { k = path[j]; path[j] = path[i - j]; path[i - j] = k; } // 输出换乘信息 printf("从%s到%s的最短路线为:\n", start, end); int curLine = -1; for (i = 0; i < n - 1; i++) { if (line[path[i + 1]] != line[path[i]]) { printf("在%s站换乘%s线路\n", path[i], line[path[i + 1]]); curLine = line[path[i + 1]]; } } printf("到达%s站\n", end); return dist[end]; } int main() { // 读入地铁线路图 scanf("%d", &n); memset(graph, INF, sizeof(graph)); int i, j, k, m; for (i = 1; i <= n; i++) { scanf("%d", &m); for (j = 0; j < m; j++) { scanf("%d", &k); if (j > 0) { graph[k][i] = graph[i][k] = 1; // 相邻站点距离为1 } } } // 读入起点和终点 int start, end; scanf("%d %d", &start, &end); // 求最短路径 int path[MAX]; int dist = dijkstra(start, end, path); // 输出结果 printf("从%s到%s的最短路线为:\n", start, end); for (i = 0; i < n; i++) { if (i == 0) printf("%s", path[i]); else printf("->%s", path[i]); } printf("\n距离为%d\n", dist); // 换乘 transfer(start, end, path); return 0; } ``` 需要注意的是,这只是一个简单的示例代码,实际情况可能更加复杂,需要根据具体情况进行修改和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值