最短路径
今天来介绍单源最短路径。所谓单源最短路径,是指在一个有向图中,从一个源点s出发,分别求出到其他各点的最短路径。我们采用迪杰斯特拉算法来实现单源最短路径。值得注意的是,迪杰斯特拉算法和prim算法很相似。迪杰斯特拉属于一种贪心思想的运用,在该算法中,图中各个节点被分为最短路树节点和非最短路树节点。
迪杰斯特拉算法的步骤如下:
1、使用一个数组d记录各点到源点s的距离,初始化距离数组为无穷大:(1 << 31)- 1。
2、确定某个源点s,将源点s加入到最短路树中,更新源点d[s] = 0。
3、以新加入最短路树的点now为顶点,更新所有与now直接相连的点到源点s的距离,也就是更新d数组。
4、在最短路树节点中找到离源点s最近的点now,将now加入到最短路树中。
5、重复步骤3、4直到完成。
下面为实现代码:
#include <iostream> #include <cstdio> using namespace std; const int MAXN = 10001; const int MAXM = 500001; const int INF = (1 << 31) - 1; struct Line { int p; int v; int next; }; struct Node { int d; bool book; }; Node node[MAXN]; Line line[MAXM]; int h[MAXN]; int n, m, s, x, y, v, now; void add(int x, int y, int v, int lID) { line[lID].p = y; line[lID].v = v; line[lID].next = h[x]; h[x] = lID; } int find() { int p = 0; for(int i = 1; i <= n; i++) { if(!node[i].book) { if(p == 0 || node[p].d > node[i].d) { p = i; } } } return p; } void update(int now) { int k = h[now]; //与now节点相连的边的编号 int p; while(k) { p = line[k].p; //编号为k的边的长度 if(!node[p].book) { if(node[p].d > line[k].v + node[now].d) { node[p].d = line[k].v + node[now].d; } } k = line[k].next; } } int main() { scanf("%d %d %d", &n, &m, &s); for(int i = 1; i <= m; i++) { scanf("%d %d %d", &x, &y, &v); add(x, y, v, i); } for(int i = 1; i <= n; i++) { node[i].book = false; node[i].d = INF; } node[s].book = true; node[s].d = 0; update(s); for(int i = 1; i < n; i++) { now = find(); node[now].book = true; update(now); } for(int i = 1; i <= n; i++) { printf("%d ", node[i].d); } return 0; }
值得注意的是,在迪杰斯特拉算法中,有一步为寻找离源点s最近,在上面的代码中我们使用的是遍历每个节点来实现的,时间复杂度为O(N),实际上,我们在这这一步可以使用堆来进行优化。关于堆的内容,在我的下一篇博客中将进行讲解。
圆满完成。