单源最短路径
百度百科
给定一个带权有向图G=(V,E),其中每条边的权是一个实数。另外,还给定V中的一个顶点,称为源。现在要计算从源到其他所有各顶点的最短路径长度。这里的长度就是指路上各边权之和。这个问题通常称为单源最短路径 [1] 问题。
问题描述
给定一个带权有向图 G=(V,E)。另外,还给定 V 中的一个顶点,称为源。现在我们要计算从源到所有其他各顶点的最短路径长度。这里的长度是指路上各边权之和。这个问题通常称为单源最短路径问题。
Dijkstra算法的解决方案
即先求出长度最短的一条最短路径,再参照它求出长度次短的一条最短路径,依次类推,直到从源点v 到其它各顶点的最短路径全部求出为止。
Dijkstra算法的解题思想
选一顶点v为源点,并视从源点v出发的所有边为到各顶点的最短路径
- 创建一个记录从源点v到其它各顶点的路径长度数组dist[],开始时,dist是源点v到顶点i的直接边长度,即dist中记录的是邻接阵的第v行
- 设一个用来记录从源点到其它顶点的路径数组path[],path中存放路径上第i个顶点的前驱顶点)。
在上述的最短路径dist[]中选一条最短的,并将其终点(即
)k加入到集合s中。 调整T中各顶点到源点v的最短路径。 因为当顶点k加入到集合s中后,源点v到T中剩余的其它顶点j就又增加了经过顶点k到达j的路径,这条路径可能要比源点v到j原来的最短的还要短。
调整方法是比较dist[k]+g[k,j]与dist[j],取其中的较小者。即算法当中的
1
2
3
4if(min + g.edges[v][k] < d[k])
{
d[k] = min + g.edges[v][k];
}
- 再选出一个到源点v路径长度最小的顶点k,从T中删去后加入S中,再回去到第三步,如此重复,直到集合S中的包含图G的所有顶点。
举个书上的题当作例子
初始化的距离向量
- 选A作为源点,A到各顶点的距离即为距离向量
A | B | C | D | E | F | G | |||
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | 0 | 48 | ∞ | 15 | 28 | ∞ | 40 |
这时候的路径向量为:
- 只有与A有点关联的结点才有路径向量为0,其他均为 -1
A | B | C | D | E | F | G | |||
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | -1 | 0 | -1 | 0 | 0 | -1 | 0 |
接下来,就是将源点A到其他结点距离最短的结点找出来,这里最短的是到D结点加到集合S当中,并且:
- 由于D的加入,导致A到F的距离由∞变为33 + 15 = 48
- A到G的距由40变为
A->D->G
= 15 + 23 = 38 - D的下标为3,所以v变为3
距离向量变为:
A | B | C | D | E | F | G | |||
---|---|---|---|---|---|---|---|---|---|
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | 0 | 48 | ∞ | 15 | 28 | ∞ | 40 |
1 | {A,D} | 3 | 0 | 48 | ∞ | 15 | 28 | 48 | 38 |
由于现在A到G和F通过了D顶点,导致顶点G和F的前驱结点变为了D,即路径向量变为3
路径向量为:
A | B | C | D | E | F | G | |||
---|---|---|---|---|---|---|---|---|---|
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | -1 | 0 | -1 | 0 | 0 | -1 | 0 |
1 | {A,D} | 3 | -1 | 0 | -1 | 0 | 0 | 3 | 3 |
接下来继续向后找,发现最短的路径是到E,所以将其加入集合S,并且:
- A到C的距离由∞变为了
A->E->C
= 28 + 33 = 61 - 其他的均未变化
距离向量变为:
A | B | C | D | E | F | G | |||
---|---|---|---|---|---|---|---|---|---|
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | 0 | 48 | ∞ | 15 | 28 | ∞ | 40 |
1 | {A,D} | 3 | 0 | 48 | ∞ | 15 | 28 | 48 | 38 |
2 | {A,D,E} | 4 | 0 | 48 | 61 | 15 | 28 | 48 | 38 |
由于A->C
变成了A->E->C
,所以C的前驱结点变为了E,即4
路径向量为:
A | B | C | D | E | F | G | |||
---|---|---|---|---|---|---|---|---|---|
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | -1 | 0 | -1 | 0 | 0 | -1 | 0 |
1 | {A,D} | 3 | -1 | 0 | -1 | 0 | 0 | 3 | 3 |
2 | {A,D,E} | 4 | -1 | 0 | 4 | 0 | 0 | 3 | 3 |
继续向下推导,最终结果为:
距离向量:
A | B | C | D | E | F | G | |||
---|---|---|---|---|---|---|---|---|---|
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | 0 | 48 | ∞ | 15 | 28 | ∞ | 40 |
1 | {A,D} | 3 | 0 | 48 | ∞ | 15 | 28 | 48 | 38 |
2 | {A,D,E} | 4 | 0 | 48 | 61 | 15 | 28 | 48 | 38 |
3 | {A,D,E,G} | 6 | 0 | 48 | 61 | 15 | 28 | 48 | 38 |
4 | {A,D,E,G,B} | 1 | 0 | 48 | 60 | 15 | 28 | 48 | 38 |
5 | {A,D,E,G,B,F} | 4 | 0 | 48 | 57 | 15 | 28 | 48 | 38 |
6 | {A,D,E,G,B,F,C} | 2 | 0 | 48 | 57 | 15 | 28 | 48 | 28 |
路径向量:
A | B | C | D | E | F | G | |||
---|---|---|---|---|---|---|---|---|---|
循环 | 集合S | v | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
初始化 | {A} | - | -1 | 0 | -1 | 0 | 0 | -1 | 0 |
1 | {A,D} | 3 | -1 | 0 | -1 | 0 | 0 | 3 | 3 |
2 | {A,D,E} | 4 | -1 | 0 | 4 | 0 | 0 | 3 | 3 |
3 | {A,D,E,G} | 6 | -1 | 0 | 4 | 0 | 0 | 3 | 3 |
4 | {A,D,E,G,B} | 1 | -1 | 0 | 1 | 0 | 0 | 3 | 3 |
5 | {A,D,E,G,B,F} | 4 | -1 | 0 | 5 | 0 | 0 | 3 | 3 |
6 | {A,D,E,G,B,F,C} | 2 | -1 | 0 | 5 | 0 | 0 | 3 | 3 |
可以从表中的数据得出:
- 由于B的路径向量为0,即A,所以A->B的最短路径就是A->B
- C的路径向量为5,即F,而F的路径向量为3,即D,D的路径向量为0,是A,所以A到C的最短路径即为 A->D->F->C
总结为:
首尾 | 最短长度 | 最短路径 |
---|---|---|
A->B | 48 | A->B |
A->C | 57 | A->D->F->C |
A->D | 15 | A->D |
A->E | 28 | A->E |
A->F | 48 | A->D->F |
A->G | 28 | A->D->G |
代码:
1 |
|