Djikstra算法

Dijkstra算法:

Dijkstra算法常用于求无负权边中的最短路,

在优化后有比Bellman-Ford算法优秀很多的时间复杂度。

同样的,我们引入记号

G = <V,E>代表一个简单有向图(简单图:没有重边和自环)

n = |V|代表顶点数

m = |E|代表边数

l(u,v)代表u到v的边权

S代表起点,T代表终点

dist(u)代表当前求出的S到u的最短路径长度


Dijkstra算法简介:

我们要维护一个顶点集合C

满足对于所有集合C中的顶点x,我们都已经找到了起点S到x的最短路

此时,dist(x)记录的就是最终最短路的长度


Dijkstra算法流程:

1. 初始化:

将C设置为空,将S的距离设置为0,其余顶点的距离设置为正无穷。

2. 更新:

每一轮中,将离起点最近的(dist最小,不能是无穷大)还不在C中的顶点加入C, 

并且用这个点连出去的边,通过松弛操作尝试更新其他点的dist。

3. 判断:

当T(如果T存在)或者没有新的点加入C时,算法结束。

 

由于图上并不存在负权边,可以证明每次加入C的点,

都已经找到了从起点到它的最短路。


 

代码实现:O(n2 + m)

复制代码
 1 const int N = 10000;
 2 
 3 struct Node{
 4     int y, v;
 5     Node(int _y, int _v){
 6         y = _y;
 7         v = _v;
 8     };
 9 };
10 
11 vector <Node> edge[N + 1];
12 int n, m, dist[N + 1];
13 bool b[N + 1];
14 
15 int Dijkstra(int s, int t){
16     memset(b, false, sizeof(b));
17     memset(dist, 127, sizeof(dist));
18     dist[s] = 0;
19     while(1){
20         int x = -1;
21         for (int i = 1;i <= n;i++){
22             if (!b[i] && dist[i] < 1 << 30){
23                 if (x == -1 || dist[i] < dist[x]){
24                     x = i;
25                 }
26             }
27         }
28         if (x == t || x == -1){
29             break;
30         }
31         b[x] = true;
32         for (auto p : edge[x]){
33             dist[p.y] = min(dist[p.y], dist[x] + p.v);
34         }
35     }
36     return dist[t];
37 }
复制代码

堆优化Dijkstra:O((n + m)log n)

复制代码
 1 //用一个堆来维护dist数组,可以使用set,也可以使用priority_queue
 2 const int N = 10000;
 3 
 4 struct Node{
 5     int y, v;
 6     Node(int _y, int _v){
 7         y = _y;
 8         v = _v;
 9     };
10 };
11 
12 set < pair<int, int>> q;
13 vector <Node> edge[N + 1];
14 int n, m, dist[N + 1];
15 
16 int Dijkstra(int s, int t){
17     memset(dist, 127, sizeof(dist));
18     dist[s] = 0;
19     q.clear();
20 
21     for (int i = 1;i <= n;i++){
22         q.insert(mp(dist[i], i));
23     }
24 
25     while(!q.empty()){
26         int x = q.begin()->second;
27         q.erase(q.begin());
28         if (x == t || dist[x] > 1 << 30){
29             break;
30         }
31         for (auto p : edge[x]){
32             if (dist[x] + p.v < dist[p.y]){
33                 q.erase(mp(dist[p.y], p.y));
34                 dist[p.y] = dist[x] + p.v;
35                 q.insert(mp(dist[p.y], p.y));
36             }
37         }
38     }
39     return dist[t];
40 }
复制代码

(未完待续......)

posted @   Conqueror712  阅读(138)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示