当前位置:   article > 正文

基于 Dijsktra(迪杰斯特拉) 算法的最短路径求值_掌握图的邻接矩阵表示法,掌握采用邻接矩阵表示法创建图的算法。 2.掌握求解最短路

掌握图的邻接矩阵表示法,掌握采用邻接矩阵表示法创建图的算法。 2.掌握求解最短路

一、实验目的

1.掌握图的邻接矩阵表示法,掌握采用邻接矩阵表示法创建图的算法。

2.掌握求解最短路径的 Dijsktra 算法。

二、实验内容

问题描述 一张地图包括 n 个城市,假设城市间有 m 条路径(有向图),每条路径的长度 已知。给定地图的一个起点城市和终点城市,利用 Dijsktra 算法求出起点到终 点之间的最短路径。 输入要求 多组数据,每组数据有 m+3 行。第一行为两个整数 n 和 m,分别代表城市 个数 n 和路径条数 m。第二行有 n 个字符,代表每个城市的名字。第三行到第 m+2 行每行有两个字符 a 和 b 和一个整数 d,代表从城市 a 到城市 b 有一条距离 为 d 的路。最后一行为两个字符,代表待求最短路径的城市起点和终点。当 n 和 m 都等于 0 时,输入结束。 输出要求 每组数据输出 2 行。第 1 行为一个整数,为从起点到终点之间最短路的长度。 第 2 行为一串字符串,代表该路径。每两个字符之间用空格隔开。 

输入样例

3 3 //三条城市三条边 

A B C// 城市的名称

A B 1// 边和权重

B C 1

C A 3

A C// 所求AC最短距离

输出样例

2// 最短路的长度

A B C// 路径

Dijkstra算法的时间复杂度取决于实现方式,但通常是O(V^2)或O((V + E) * log(V)),其中V是顶点数,E是边数。在使用最小堆(优先队列)等数据结构进行优化时,算法的时间复杂度可以降低。

假设读者已了解算法具体过程,下面给出实现代码

1. 图的邻接矩阵存储表示:

  1. #define MVNum 100
  2. #define MaxInt 32767
  3. typedef struct {
  4. char vex[MVNum]; // 顶点表
  5. int arcs[MVNum][MVNum]; // 邻接矩阵,权重为整数
  6. int Vexnum; // 顶点数
  7. int arcnum; // 边数
  8. } AMGraph;

2.对G进行初始化

  1. void initG(AMGraph& G, int n) {
  2. int Max = numeric_limits<int>::max();// 取较大值代替无穷
  3. // 对邻接矩阵进行初始化
  4. for (int i = 0; i < n; i++) {
  5. for (int j = 0; j < n; j++) {
  6. G.arcs[i][j] = Max;
  7. }
  8. }
  9. }

3.对G进行输入

  1. void inputG(AMGraph& G, int n, int m) {
  2. // 对城市进行录入
  3. for (int i = 0; i < n; i++) {
  4. cin >> G.vex[i];
  5. }
  6. initG(G, n);
  7. // 输入路径信息
  8. for (int i = 0; i < m; i++) {
  9. char a, b;
  10. int d;
  11. cin >> a >> b >> d;
  12. int index_a = find(G.vex, G.vex + n, a) - G.vex;// G.vex为起始位置,迭代器获取a的索引
  13. int index_b = find(G.vex, G.vex + n, b) - G.vex;// G.vex为起始位置,迭代器获取b的索引
  14. G.arcs[index_a][index_b] = d;
  15. }
  16. }

3.Dijsktra代码实现过程

  1. void Dijkstra(AMGraph G, int start, int end, int& minDist, vector<int>& path) {
  2. int Max = numeric_limits<int>::max();// 取较大值代替无穷
  3. vector<int> dist(G.Vexnum, Max); // 用于存储起点到各顶点的最短距离
  4. vector<bool> visited(G.Vexnum, false); // 记录顶点是否已访问
  5. vector<int> Path(G.Vexnum, -1); // 记录路径上的前驱节点
  6. dist[start] = 0;// 起点到起点的距离设为零
  7. for (int i = 0; i < G.Vexnum; ++i) {
  8. int minIndex = -1;// 当前阶段找到的最小距离的顶点的索引
  9. int minDistance = Max;// 最小的距离,初始化为无穷
  10. // 选取未访问的顶点中距离最小的顶点
  11. for (int j = 0; j < G.Vexnum; ++j) {
  12. if (!visited[j] && dist[j] < minDistance) {
  13. minIndex = j;
  14. minDistance = dist[j];
  15. }
  16. }
  17. if (minIndex == -1) {
  18. break; // 所有顶点都被访问过
  19. }
  20. visited[minIndex] = true;// 将当前已经访问的节点置为true
  21. // 更新与选取顶点相邻的顶点的最短距离
  22. for (int k = 0; k < G.Vexnum; ++k) {
  23. // 如果顶点 k 未被访问且存在从当前顶点 minIndex 到顶点 k 的边
  24. if (!visited[k] && G.arcs[minIndex][k] < Max) {
  25. int newDist = dist[minIndex] + G.arcs[minIndex][k];// 计算从起点经过 minIndex 到达顶点 k 的新路径长度
  26. if (newDist < dist[k]) {
  27. dist[k] = newDist; // 更新起点到顶点 k 的最短路径长度
  28. Path[k] = minIndex; // 记录顶点 k 在最短路径上的前驱顶点为 minIndex
  29. }
  30. }
  31. }
  32. }
  33. minDist = dist[end];// 记录从起点到终点的最短路径长度
  34. int vi = end;// vi 为终点 end 在顶点表 vex[] 中的索引
  35. // 从终点开始反向遍历最短路径上的各个顶点
  36. while (vi != -1) {
  37. path.push_back(vi);// 将当前顶点 vi 添加到路径中
  38. vi = Path[vi]; // 获取当前顶点 vi 在最短路径上的前驱顶点的索引
  39. }
  40. reverse(path.begin(), path.end()); // 反转路径,使起点到终点的顺序正确
  41. }

完整代码实现

  1. #include <iostream>
  2. #include <climits>
  3. #include <vector>
  4. #include <algorithm>
  5. using namespace std;
  6. #define MVNum 100
  7. #define MaxInt 32767
  8. typedef struct {
  9. char vex[MVNum]; // 顶点表
  10. int arcs[MVNum][MVNum]; // 邻接矩阵,权重为整数
  11. int Vexnum; // 顶点数
  12. int arcnum; // 边数
  13. } AMGraph;
  14. // 对G进行初始化
  15. void initG(AMGraph& G, int n) {
  16. int Max = numeric_limits<int>::max();// 取较大值代替无穷
  17. // 对邻接矩阵进行初始化
  18. for (int i = 0; i < n; i++) {
  19. for (int j = 0; j < n; j++) {
  20. G.arcs[i][j] = Max;
  21. }
  22. }
  23. }
  24. // 对G进行输入
  25. void inputG(AMGraph& G, int n, int m) {
  26. // 对城市进行录入
  27. for (int i = 0; i < n; i++) {
  28. cin >> G.vex[i];
  29. }
  30. initG(G, n);
  31. // 输入路径信息
  32. for (int i = 0; i < m; i++) {
  33. char a, b;
  34. int d;
  35. cin >> a >> b >> d;
  36. int index_a = find(G.vex, G.vex + n, a) - G.vex;// G.vex为起始位置,迭代器获取a的索引
  37. int index_b = find(G.vex, G.vex + n, b) - G.vex;// G.vex为起始位置,迭代器获取b的索引
  38. G.arcs[index_a][index_b] = d;
  39. }
  40. }
  41. void Dijkstra(AMGraph G, int start, int end, int& minDist, vector<int>& path) {
  42. int Max = numeric_limits<int>::max();// 取较大值代替无穷
  43. vector<int> dist(G.Vexnum, Max); // 用于存储起点到各顶点的最短距离
  44. vector<bool> visited(G.Vexnum, false); // 记录顶点是否已访问
  45. vector<int> Path(G.Vexnum, -1); // 记录路径上的前驱节点
  46. dist[start] = 0;// 起点到起点的距离设为零
  47. for (int i = 0; i < G.Vexnum; ++i) {
  48. int minIndex = -1;// 当前阶段找到的最小距离的顶点的索引
  49. int minDistance = Max;// 最小的距离,初始化为无穷
  50. // 选取未访问的顶点中距离最小的顶点
  51. for (int j = 0; j < G.Vexnum; ++j) {
  52. if (!visited[j] && dist[j] < minDistance) {
  53. minIndex = j;
  54. minDistance = dist[j];
  55. }
  56. }
  57. if (minIndex == -1) {
  58. break; // 所有顶点都被访问过
  59. }
  60. visited[minIndex] = true;// 将当前已经访问的节点置为true
  61. // 更新与选取顶点相邻的顶点的最短距离
  62. for (int k = 0; k < G.Vexnum; ++k) {
  63. // 如果顶点 k 未被访问且存在从当前顶点 minIndex 到顶点 k 的边
  64. if (!visited[k] && G.arcs[minIndex][k] < Max) {
  65. int newDist = dist[minIndex] + G.arcs[minIndex][k];// 计算从起点经过 minIndex 到达顶点 k 的新路径长度
  66. if (newDist < dist[k]) {
  67. dist[k] = newDist; // 更新起点到顶点 k 的最短路径长度
  68. Path[k] = minIndex; // 记录顶点 k 在最短路径上的前驱顶点为 minIndex
  69. }
  70. }
  71. }
  72. }
  73. minDist = dist[end];// 记录从起点到终点的最短路径长度
  74. int vi = end;// vi 为终点 end 在顶点表 vex[] 中的索引
  75. // 从终点开始反向遍历最短路径上的各个顶点
  76. while (vi != -1) {
  77. path.push_back(vi);// 将当前顶点 vi 添加到路径中
  78. vi = Path[vi]; // 获取当前顶点 vi 在最短路径上的前驱顶点的索引
  79. }
  80. reverse(path.begin(), path.end()); // 反转路径,使起点到终点的顺序正确
  81. }
  82. int main() {
  83. int n;// 城市的个数
  84. int edge;// 有向边
  85. cin >> n >> edge;
  86. AMGraph G;// 创建图G
  87. // 图G参数赋值
  88. G.Vexnum = n;
  89. G.arcnum = edge;
  90. inputG(G, n, edge);
  91. char start;// 起始目标节点
  92. char end;// 终止目标节点
  93. cin >> start >> end;
  94. int minDist;// 存储目标结点间最短路径
  95. vector<int> path;// 存储从起点到终点的最短路径上的顶点序列
  96. int startIndex = find(G.vex, G.vex + n, start) - G.vex;// 迭代器,计算start索引
  97. int endIndex = find(G.vex, G.vex + n, end) - G.vex;// 迭代器, 计算end索引
  98. Dijkstra(G, startIndex, endIndex, minDist, path);
  99. // 输出结果
  100. cout << minDist << endl;
  101. for (int i = 0; i < path.size(); ++i) {
  102. cout << G.vex[path[i]];
  103. if (i < path.size() - 1) {
  104. cout << " ";
  105. }
  106. }
  107. cout << endl;
  108. return 0;
  109. }

运行结果

输入为

  1. 3 3
  2. A B C
  3. A B 1
  4. B C 1
  5. C A 3
  6. A C

输出

  1. 2
  2. A B C

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/711064
推荐阅读
相关标签
  

闽ICP备14008679号