算法学习笔记(7.7)-贪婪算法(Dijkstra算法-最短路径问题) ...

打印 上一主题 下一主题

主题 761|帖子 761|积分 2293

目次
1.最短路径问题
 2.Dijkstra算法先容
 3.Dijkstra算法演示
4.Dijkstra算法的代码示例


1.最短路径问题

   图论中的一个经典问题,通常是指在一个加权图中找到从一个起始顶点到目标顶点的最短路径。
  

  • 单源最短路径问题:给定一个加权图和一个起始顶点,要找到从该起始顶点到图中所有其他顶点的最短路径。

    • Dijkstra算法:适用于没有负权边的图,能够找到单源最短路径。
    • Bellman-Ford算法:适用于存在负权边的图,能够找到单源最短路径。

  • 全源最短路径问题:给定一个加权图,要找到图中恣意两个顶点之间的最短路径。

    • Floyd-Warshall算法:适用于有向图或无向图,能够找到所有顶点之间的最短路径。

  • 最短路径问题的应用

    • 在网络路由中,确定数据包的最佳路径。
    • 在地图应用程序中,找到两个地点之间的最短驾驶路径。
    • 在交通规划中,优化公交线路或货运路径。
    • 在电路设计中,找到电路中信号传输的最短路径。

  • 解决最短路径问题的算法

    • Dijkstra算法:适用于非负权重的图,能够找到单源最短路径。
    • Bellman-Ford算法:适用于存在负权重的图,能够找到单源最短路径。
    • A*算法:一种开导式搜刮算法,用于探求从起点到目标点的最短路径。
    • Bellman-Ford算法:适用于有向图或无向图,能够找到所有顶点之间的最短路径。

   2.Dijkstra算法先容

   1.Dijkstra算法特点:
  迪科斯彻算法使用了广度优先搜刮解决赋权有向图大概无向图的单源最短路径问题,算法终极得到一个最短路径树。该算法常用于路由算法大概作为其他图算法的一个子模块。
  
  2.Dijkstra算法的步骤:
  2.1 初始化:创建一个空的集合用于存储已经找到最短路径的顶点,以及一个数组用于存储从起始顶点到每个顶点的最短距离。将起始顶点的最短距离设置为0,其他顶点的最短距离设置为无穷大。
  2.2 选取起始顶点:将起始顶点参加集合,更新起始顶点到相邻顶点的最短距离。
  2.3 重复步骤:重复以下步骤,直到所有顶点都被参加集合为止:
   2.3.1 从未参加集合的顶点中选取与起始顶点距离最短的顶点参加集合。
   2.3.2 更新该顶点到相邻顶点的最短距离,如果经过该顶点到相邻顶点的距禒小于已知的最短距离,则更新最短距离。
  2.4 终极结果:当所有顶点都被参加集合后,最短路径就被找到了。
  
  3. Dijkstra算法的特点和适用性:
  3.1 Dijkstra算法适用于带权重的有向图或无向图。
3.2 该算法包管找到的路径是最短的,但条件是图中不能有负权重的边
3.3 时间复杂度取决于详细实现,通常在稠密图上的时间复杂度为O(V^2),在稀疏图上的时间复杂度为O(E * log V)。
3.4 Dijkstra算法常用于路由算法、网络分析、地图应用等领域。
  
  4. Dijkstra核心算法思想:
  迪杰斯特拉算法主要特点是从起始点开始,采用贪婪算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止
   3.Dijkstra算法演示

   1.用一个 dist 数组生存源点到别的各个节点的距离,dist 表现源点到节点 i 的距离。初始时,dist 数组的各个元素为无穷大。用一个状态数组 state 记录是否找到了源点到该节点的最短距离,state 如果为真,则表现找到了源点到节点 i 的最短距离,state 如果为假,则表现源点到节点 i 的最短距离还没有找到。初始时,state 各个元素为假。

  2.源点到源点的距离为 0。即dist[1] = 0。

  3.遍历 dist 数组,找到一个节点,这个节点是:没有确定最短路径的节点中距离源点最近的点。假设该节点编号为 i。此时就找到了源点到该节点的最短距离,state 置为 1。
  

  4.遍历 i 所有可以到达的节点 j,如果 dist[j] 大于 dist 加上 i -> j 的距离,即 dist[j] > dist + w[j](w[j] 为 i -> j 的距离) ,则更新 dist[j] = dist + w[j]。

  5.重复 3 4 步骤,直到所有节点的状态都被置为 1。
  

6.此时 dist 数组中,就生存了源点到别的各个节点的最短距离。
  

  4.Dijkstra算法的代码示例

  
  1. //c++代码实现
  2. #include <iostream>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <vector>
  6. using namespace std;
  7. const int N = 510, M = 100010, INF = 0x3f3f3f3f;
  8. int h[N], e[M], ne[M], w[M], idx;
  9. //h数组用来储存每个边链表的头部
  10. //e数组用来存储每条边指向的节点编号
  11. //w用来存储每条边的权重
  12. //ne数组用来实现邻接表中的链表结构
  13. int dist[N]; //state 记录是否找到了源节点到该节点的最短距离
  14. bool state[N]; //dist 数组保存源点到其余各个节点的距离
  15. int n, m; //图的节点个数和边数
  16. int adjMatrix[N][N];  // 邻接矩阵
  17. void add(int a, int b, int c)
  18. {
  19.         e[idx] = b ; //将当前边的目标节点b存储在,e[idx]中
  20.         w[idx] = c ; //将该条边的权重存储在,w[idx]中
  21.         ne[idx] = h[a] ; //更新ha将之前节点a的第一条边的索引存储在ne数组,使其一直处于更新状态指向最新的一条边
  22.         h[a] = idx++ ;       
  23. }
  24. // 打印邻接表
  25. void printAdjList() {
  26.     for (int i = 1; i <= n; ++i) {
  27.         cout << "Vertex " << i << ":";
  28.         for (int j = h[i]; j != -1; j = ne[j]) {
  29.             cout << "-> (" << e[j] << ", " << w[j] << ")";
  30.         }
  31.         cout << endl;
  32.     }
  33. }
  34. // 创建并打印邻接矩阵
  35. void printAdjMatrix() {
  36.     // 初始化邻接矩阵
  37.     for (int i = 1; i <= n; ++i) {
  38.         for (int j = 1; j <= n; ++j) {
  39.             if (i == j) adjMatrix[i][j] = 0;
  40.             else adjMatrix[i][j] = INF;
  41.         }
  42.     }
  43.    
  44.     // 填充邻接矩阵
  45.     for (int i = 1; i <= n; ++i) {
  46.         for (int j = h[i]; j != -1; j = ne[j]) {
  47.             int to = e[j];
  48.             adjMatrix[i][to] = min(adjMatrix[i][to], w[j]);  // 如果有重边,保留权重最小的一条
  49.         }
  50.     }
  51.    
  52.     // 打印邻接矩阵
  53.     for (int i = 1; i <= n; ++i) {
  54.         for (int j = 1; j <= n; ++j) {
  55.             if (adjMatrix[i][j] == INF) cout << "INF ";
  56.             else cout << adjMatrix[i][j] << " ";
  57.         }
  58.         cout << endl;
  59.     }
  60. }
  61. void Dijkstra()
  62. {
  63.         memset(dist, 0x3f, sizeof(dist)) ; //dist 初始化数组中的元素为最大值
  64.         dist[1] = 0 ;
  65.         for (int i = 0 ; i < n ; i++)
  66.         {
  67.                 int t = -1 ;
  68.                 for (int j = 1 ; j <= n ; j++)
  69.                 {
  70.                         //遍历 dist 数组,找到没有确定最短路径的节点
  71.                         if (!state[j] && (t == -1 || dist[j] < dist[t]))
  72.                         {
  73.                                 t = j ;       
  74.                         }
  75.                 }
  76.                 state[t] = 1 ; //将该位置置为访问
  77.                        
  78.                 for (int j = h[t]; j != -1 ; j = ne[j]) //遍历 t 所有可以到达的节点i
  79.                 {
  80.                         int i = e[j] ;
  81.                         dist[i] = min(dist[i], dist[t] + w[j]) ; //更新dist[j]
  82.                 }       
  83.                        
  84.         }
  85. }
  86. int main()
  87. {
  88.         memset(h, -1, sizeof(h)) ;
  89.        
  90.         cin >> n >> m ;
  91.         while (m--)
  92.         {
  93.                 int a, b, w ;
  94.                 cin >> a >> b >> w ;
  95.                 add(a, b, w) ;
  96.         }
  97.         Dijkstra() ;
  98.         if (dist[n] != 0x3f3f3f3f)
  99.         {
  100.                 cout << dist[n] ;
  101.         }
  102.         else
  103.         {
  104.                 cout << "-1" ;
  105.         }
  106.         // 打印邻接表
  107.     printAdjList();
  108.     // 创建并打印邻接矩阵
  109.     printAdjMatrix();
  110.         return 0 ;
  111. }
复制代码

  1. #python代码示例
  2. # 简单的Dijkstra算法
  3. import heapq
  4. def dijkstra(graph, start) :
  5.     # 初始化距离字典,将所有节点的距离设置为无穷大
  6.     distances = {node : float('inf') for node in graph}
  7.     # 源节点到自身的距离设置为0
  8.     distances[start] = 0
  9.     # 使用优先队列来进行优化,队列中的元素(距离,节点)
  10.     priority_queue = [(0,start)]
  11.     while priority_queue :
  12.         # 弹出队列中最小距离的节点
  13.         current_distance, current_node = heapq.heappop(priority_queue)
  14.         # 如果弹出的节点距离大于当前记录的距离,则忽略(已找到更短路径)
  15.         if current_distance > distances[current_node] :
  16.             continue
  17.         # 遍历相邻的节点,更新距离
  18.         for neighbor, weight in graph[current_node].items() :
  19.             distance = current_distance + weight
  20.             # 如果通过当前节点到达相邻节点的距离更短,则更新距离字典和最小堆
  21.             if distance < distances[neighbor] :
  22.                 distances[neighbor] = distance
  23.                 heapq.heappush(priority_queue,(distance,neighbor))
  24.                 print(f"更新节点: {neighbor} 的最短路径为: {distance}")
  25.     return distances
  26. graph = {
  27. 'A': {'B': 1, 'C': 3},
  28. 'B': {'A': 1, 'C': 1, 'D': 4},
  29. 'C': {'A': 3, 'B': 2, 'D': 1},
  30. 'D': {'B': 4, 'C': 1}
  31. }
  32. start = 'A'
  33. # print(dijkstra(graph, start))  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
  34. shortest_paths = dijkstra(graph, start)
  35. print("\n从节点 {} 到图中其他节点的最短路径:".format(start))
  36. for node, distance in shortest_paths.items():
  37.     print(f"到节点 {node} 的最短距离是: {distance}")
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

来自云龙湖轮廓分明的月亮

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表