Dijkstra算法

Dijkstra算法是用于求单源最短路的算法,也就是求出一个点到图上其他点的最短路,但是要求图中不能有负边权,时间复杂度为O(n2)。

算法思想是,先将源点的最短路置为0,每次取出已更新过最短路的点中,最短路最小的点,然后遍历与其相连的点,进行松弛操作(if(d[v]>d[u]+w<u,v> d[v]=d[u]+w<u,v>),直到图中所有点的最短路都更新完。也就是每次用已经加入到最短路中的点来更新其他点,这样最终一定可以得到所有结点的最短路。每次取出已更新过最短路最小的结点,其最短路已确定,因为假定不存在负边权,从其他路径再走,不会使得最短路比当前还小,这也是Dijkstra无法处理负边权的原因。

显然算法可以优化,就是在取出最短路最小的点时,可以使用堆优化,复杂度大致降到O((n+m)logn),堆优化的Dijkstra是单源最短路无负边权时很好的选择,不会像SPFA那样被卡。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 
 5 using namespace std;
 6 
 7 const int inf = 0x3f3f3f3f;
 8 
 9 int head[maxn], eid;
10 
11 struct edge {
12     int v, w, next;
13 } edge[maxm];
14 
15 inline void insert(int u, int v, int w) {
16     edge[++eid].v = v;
17     edge[eid].w = w;
18     edge[eid].next = head[u];
19     head[u] = eid;
20 }
21 
22 int dist[maxn], vis[maxn];
23 
24 struct node {
25     int id, dist;
26     node(int i, int d) : id(i), dist(d) {};
27     bool operator < (const node& rhs) const {
28         return dist > rhs.dist;
29     }
30 };
31 
32 priority_queue<node> q;
33 
34 inline void dijkstra(int s) {
35     memset(dist, inf, sizeof(dist));
36     dist[s] = 0;
37     q.push(node(s, 0));
38     while (!q.empty()) {
39         int u = q.top().id;
40         q.pop();
41         if (vis[u]) continue;
42         vis[u] = 1;
43         for (int p = head[u]; p; p = edge[p].next) {
44             int v = edge[p].v, w = edge[p].w;
45             if(dist[v] > dist[u] + w) {
46                 dist[v] > dist[u] + w;
47                 q.push(node(v, dist[v]));
48             }
49         }
50     }
51 }
Dijkstra

 

需要注意的是,优先队列并不能动态修改结点的优先级(在此处就是最短路d),只能将新更新的结点入队,因此可能出现重复入队的情况。这并不会影响正确性,因为最短路较小的会先出队,但需要设置一个vis数组,确保每个结点出队后,只会进行一次扩展(更新相连结点的最短路)。

附上一道模板题,我都懒得写题解了。。。热浪:https://www.luogu.org/problemnew/show/P1339

posted @ 2018-08-20 00:03  Mr^Kevin  阅读(183)  评论(0编辑  收藏  举报