最短路径算法----Dijkstra
最近上图论,学了单源最短路径的Dijkstra算法。
Dijkstra算法的核心思想是贪心策略+动态规划。
老师只字不提思想,硬分析过程还是有点@#$%的。
结果就是,原先我还挺懂的,听完就凌乱了。
在这里写一下吧
=================================================
参考资料:
Wikipedia:http://en.wikipedia.org/wiki/Dijkstra's_algorithm
Nocow:http://www.nocow.cn/index.php/Dijkstra%E7%AE%97%E6%B3%95
CLRS
《算法设计与分析》
=================================================
算法流程:
在以下说明中,s为源,w[u,v]为点u和v之间的边的长度,结果保存在dis[]
初始化:源的距离dis[s]设为0,其他的点距离设为无穷大(实际程序里设成-1了),同时把所有的点的状态设为没有扩展过。
循环n-1次:
- 在没有扩展过的点中取一距离最小的点u,并将其状态设为已扩展。
- 对于每个与u相邻的点v,执行Relax(u,v),也就是说,如果dis[u]+map[u,v]<dis[v],那么把dis[v]更新成更短的距离dis[u]+w[u,v]。此时到点v的最短路径上,前一个节点即为u。
- 结束。此时对于任意的u,dis[u]就是s到u的距离。
wiki上有个很好的图,可以帮助理解算法过程:
测试数据来自清华的紫皮算法书,如下:
迭代过程如下:
迭代 |
S |
U |
dis[2] |
dis[3] |
dis[4] |
dis[5] |
初始 |
{1} |
--- |
10 |
-1 |
30 |
100 |
1 |
{1,2} |
2 |
10 |
60 |
30 |
100 |
2 |
{1,2,4} |
4 |
10 |
50 |
30 |
90 |
3 |
{1,2,4,3} |
3 |
10 |
50 |
30 |
60 |
4 |
{1,2,4,3,5} |
5 |
10 |
50 |
30 |
60 |
看上面的两个图,基本就能把Dijkstra算法的具体过程了解清楚。
算法正确性证明可以看Wiki和CLRS。
程序如下(测试数据就是上面的,输出了6个结果):
int dijk(int s, int e);函数返回从s到e的最短路。
1 #include <stdio.h> 2 #include <limits.h> 3 #include <string.h> 4 5 const int n = 6; 6 int map[n][n]; 7 8 int dijk(int s, int e) 9 { 10 int dis[n]; 11 int used[n] = {0}; 12 int min, next; 13 memset(dis, 255, sizeof(dis));//把所有未更新的dis[]设置成-1 14 15 dis[s] = 0; //从s开始 16 17 for (int i=1; i<n; ++i) 18 { 19 min = INT_MAX; 20 for (int j=1; j<n; ++j) 21 { 22 if (!used[j] && dis[j]!=-1 && dis[j]<min) 23 { 24 min = dis[j]; 25 next = j; 26 } 27 } 28 if (min != INT_MAX) 29 { 30 used[next] = 1; 31 for (int j=1; j<n; ++j) 32 { 33 if (!used[j] && map[next][j]!=-1 && 34 (dis[j]>map[next][j]+dis[next] || dis[j]==-1)) 35 { 36 dis[j] = map[next][j] + dis[next]; 37 } 38 } 39 } 40 } 41 return dis[e]; 42 } 43 44 45 int main() 46 { 47 for (int i=1; i<n; ++i) 48 { 49 for (int j=1; j<n; ++j) 50 { 51 map[i][j] = -1; 52 } 53 } 54 55 map[1][2] = 10; 56 map[1][4] = 30; 57 map[1][5] = 100; 58 map[2][3] = 50; 59 map[3][5] = 10; 60 map[4][3] = 20; 61 map[4][5] = 60; 62 63 printf("%d %d %d %d %d %d\n", dijk(1, 5), dijk(2, 3), dijk(1, 5), dijk(4, 5), dijk(1, 2), dijk(2, 4)); 64 65 66 return 0; 67 }