龙空技术网

Dijkstra 单源最短路径算法

好课堂数学编程陈老师 54

前言:

而今咱们对“数据结构图的最短路径算法有哪些”大致比较重视,你们都想要知道一些“数据结构图的最短路径算法有哪些”的相关知识。那么小编同时在网上搜集了一些有关“数据结构图的最短路径算法有哪些””的相关资讯,希望姐妹们能喜欢,咱们一起来学习一下吧!

1 Dijkstra 算法

Dijkstra算法Dijkstra 算法:采用贪心策略,可以解决单源最短路径问题适用要求:图中不存在负权边算法可以简单概括为 Dijkstra = BFS + 贪心

算法步骤

设置初始状态:S 只包含源点,U 包含除源点外的其他顶点U 中顶点v的距离为:若 v 与 s 邻接,距离为 s 到 v 的弧的权值,否则为 INF从 U 中选出距离 s 最近的顶点 u,并将顶点 u 加入到 S 中;同时,从 U 中移除顶点 u。更新 U 中各个顶点到源点s的距离。(松弛操作)重复步骤 2 和 3,直到遍历完所有顶点。

松弛操作

dis[i] 为起点 s 到 i 的最短距离。

if (dis[v] > dis[u] + w(u,v))

dis[v] = dis[u] + w(u,v)

2 算法图解

起点 0,终点 4selected 为已被标记的点dis[i] 为从起点到达 i 的最短距离,初始值都是无穷大parent[i] 为结点 i 的父节点

初始化,将起点加入到被标记的集合中,起点距离自身的距离为 0。

当 0 号点被选中,可以松弛其邻接点 1 和 7。

在未被标记的点中,找到距离起点最近的点是 1。

将点 1 标记。

点 1 可以松弛操作点 2 和点 7。

在未被标记的点中,找到距离起点最近的点是 7。

将点 7 标记。

点 1 可以松弛操作点 6 和点 8。

在未被标记的点中,找到距离起点最近的点是 6。

点 1 可以松弛操作点 5 和点 8。

在未被标记的点中,找到距离起点最近的点是 5。

将点 5 标记。

点 1 可以松弛操作点 2、点 3 和点 4。

在未被标记的点中,找到距离起点最近的点是 2。

将点 2 标记。

点 2 可以松弛操作点 3 和点 8。

在未被标记的点中,找到距离起点最近的点是 8。

将点 8 标记。

点 8 不能再松弛其它点,在未被标记的点中,找到距离起点最近的点是 4。

将点 4 标记。

3 时间复杂度

4 随堂检测

A、16

B、19

C、20

D、22

(点击选项查看答案)

5 Dijkstra为什么边的权值不能为负数?

因为 Dijkstra 基于 BFS,计算过程是从起点 s 逐步扩散的过程,每扩散一次就用贪心法得到一个点的最短路径。扩散要求路径越来越长,如果遇到一条负边权,会导致路径变短,使扩散失效。

如图所示:设当前得到 s→u 的最短路径,路径长度为 8,此时 s→u 路径计算结束。继续扩展 u 的邻居,若 u 到邻居 v 的边权为 -15,而 v 到 s 距离为 20,那么 u 存在另一条途径到 s ,距离为 20+(-15)=5,这推翻了前面已经得到的长度为 8 的最短路径,破坏了 BFS 的扩散过程。

6

编程实战

单源最短路径朴素版

题目解析:邻接矩阵,时间复杂度

参考程序

#include <bits/stdc++.h>  using namespace std; const int N = 510, INF = 0x3f3f3f3f;int n, m;int g[N][N];int dis[N];bool book[N];int dijkstra(){ memset(dis, 0x3f, sizeof dis); dis[1] = 0;  for(int i = 1; i <= n; i++){  int u = -1;  for(int j = 1; j <= n; j++){   if(!book[j] && (u == -1 || dis[j] < dis[u])){    u = j;    // dis[u] = dis[j];   }  }  book[u] = true;  for(int v = 1; v <= n; v++){   if(dis[v] > dis[u] + g[u][v])    dis[v] = dis[u] + g[u][v];  } } if(dis[n] == INF)  dis[n] = -1; return dis[n];}int main(){ memset(g, 0x3f, sizeof g);  cin >> n >> m; while(m--){  int a, b, c;  cin >> a >> b >> c;  g[a][b] = min(g[a][b], c); } for(int i = 1; i <= n; i++) g[i][i] = 0;  cout << dijkstra();  return 0;}

单源最短路径进阶版

题目解析:邻接表,时间复杂度

参考程序

#include <bits/stdc++.h>using namespace std;const int N = 2e5 + 10, INF = 0x3f3f3f3f;typedef pair<int, int> PII;struct Edge{ int w, to, next;}edge[N];int h[N];int n, m;int dis[N];bool book[N];int cnt = 0;void add(int a, int b, int c){ edge[cnt].to = b; edge[cnt].w = c; edge[cnt].next = h[a]; h[a] = cnt++;}int dijkstra(){ memset(dis, 0x3f, sizeof dis); dis[1] = 0; priority_queue<PII, vector<PII>, greater<PII> > q; q.push({0, 1}); while(q.size()){  PII t = q.top();  q.pop();  int u = t.second;  if(book[u]) continue;  book[u] = true;  for(int i = h[u]; ~i; i = edge[i].next){   int v = edge[i].to;   if(dis[v] > dis[u] + edge[i].w){    dis[v] = dis[u] + edge[i].w;    q.push({dis[v], v});   }  } } if(dis[n] == INF) dis[n] = -1; return dis[n];}int main() {        memset(h, -1, sizeof h);    cin >> n >> m;    while (m--) {        int a, b, c;        cin >> a >> b >> c;        add(a, b, c);    }    cout << dijkstra() << endl;    return 0;}

标签: #数据结构图的最短路径算法有哪些