迪杰斯特拉(Dijkstra)算法描述及其正确性证明
2014-09-06 23:03
253 查看
1. 算法描述
Dijkstra算法是图论中常用的一个算法,用于计算图中从一个指定点到其余所有点的最短路径。图是有向图,所有边的权重为非负数,图1是满足条件的一个简单有向图。
图1 有向加权图示例
在图1中,A到D的最短路径是A-->C-->B-->D,其长度为3+2+5=10。
其算法实现代码如下(数据结构与算法分析C++版):
算法中的每个结点使用整数表示,数组D[ ]定义了从出发点s到每个点v的最短路径,被初始化为INFINITY。另外,每个结点还有一个标识(Mark),通过函数setMark和getMark来设置和读取。标识具有两种状态:VISITED和UNVISITED。算法的工作步骤被描述如下:
1. 把所有结点的标识都设为UNVISITED,距离设为INFINIT。
2. 把出发点s的距离设置为0,状态设置为VISITED。
3. 从图中所有UNVISITED的点中选择距离最小的结点v。
4. 设置v的状态为VISITED。
5. 用v来更新其相邻结点。若某相邻结点u的当前距离D[u] > D[v] + weight(v, u),则把u的距离D[u]更新为D[v] + weight(v, u)。
6. 重复3到5步的操作,直到所有结点状态都被设置为VISITED。
以图1为例,算法的计算过程为:
1. D[A] = 0。
2. 选择D[A]为距离最小的结点,设其状态为VISITED;更新D = 10, D[C] = 3, D[D] = 20。
3. 选择D[C]为距离最小的结点,设其状态为VISITED;更新D[B] = D[C] + weight(C, B) = 3 + 2 = 5, D[E] = D[C] + weight(C, E) = 3 + 15 =18。
4. 选择D[B]为距离最小的结点,设其状态为VISITED;更新D[D] = D[B] + weight(B, D) = 5 + 5 = 10。
5. 选择D[D]为距离最小的结点,设其状态为VISITED;与D相连的结点E的距离D[E] = 18,小于D[D] + weight(D, E) = 10 + 11 = 21,所以不需要更新。
6. 选择D[D]为距离最小的结点,设其状态为VISITED;没有相连的点,所以不需要更新。
所以最终每个点的最小距离为D[A] = 0; D[B] = 5]; D[C] = 3]; D[D] = 10; D[E] = 18.
[b]2. 算法正确性证明
上一节描述的Dijkstra算法把图中的结点分为两个部分,分别标记为VISITED和UNVISITED,使用S和V-S来表示。为证明的方便,区分了S和V-S中的点的距离函数,分别为D和D_est,V-S中的距离函数被称为估值函数。算法的主要操作是循环执行第3到5步。证明算法的正确性,可以通过证明每次循环执行之前,S和V-S中的结点满足以下3条属性,执行之后依然满足。
属性1. S中任意m的点的的路径长度D[m]就是其最短路径。
属性2. 估值函数满足下述条件:
也就是说,对于V-S中的任意结点n,其估值路径D_est
是其只通过S中结点的最短路径。
属性3. V-S中估值最小的点n,D_est
的值就是其最短路径。
算法第一步S={s},只包含出发结点,且D[s]=0,故而满足属性1,更新相邻结点之后,容易证明,也满足属性2。属性3则需要证明,过程如下。
证明:假设D_est
不是n的最短路径,因为D_est是只通过S中结点的最短路径,所以结点n的真实的最短路径必然会经过集合S之外的结点,设路径上第一个非S中的点为j。则真实的最短路径的形式为s->...->j->...->n。因为假设了j之前的点都是S中的,所以根据属性2,D_est[j] < =D
< D_est
,与n是估值最小的结点矛盾,所以属性成立。
算法接下来的操作是把n加入S,并试图更新V-S中结点的距离估值,容易证明,3-5步的一次操作之后,属性1-3仍然满足,所以得证。
Dijkstra算法是图论中常用的一个算法,用于计算图中从一个指定点到其余所有点的最短路径。图是有向图,所有边的权重为非负数,图1是满足条件的一个简单有向图。
图1 有向加权图示例
在图1中,A到D的最短路径是A-->C-->B-->D,其长度为3+2+5=10。
其算法实现代码如下(数据结构与算法分析C++版):
void Dijkstra(Graph *G, int *D, int s){ int i, v, w; for(i = 0; i < G->n(); i++){ D[i] = INFINITY; } D[0] = 0; for(i = 0; i < G->n(); i++){ v = minVertex(G, D); if(D[v] == INFINITY) return; G->setMark(v, VISITED); for(w = G->first(v); w < G->n(); w = G->next(v, w)) if(D[w] > (D[v] + G->weight(v,w))) D[w] = D[v] + G->weight(v, w); } } int minVertex(Graph *G, int *D){ int i, v=-1; for(i = 0; i < G->n(); i++){ if(G->getMark(i) == UNVISITED){ v = i; break; } } for(i++; i < G->n(); i++){ if((G->getMark(i) == UNVISITED) && (D[i] < D[v])) v = i; } return v; }
算法中的每个结点使用整数表示,数组D[ ]定义了从出发点s到每个点v的最短路径,被初始化为INFINITY。另外,每个结点还有一个标识(Mark),通过函数setMark和getMark来设置和读取。标识具有两种状态:VISITED和UNVISITED。算法的工作步骤被描述如下:
1. 把所有结点的标识都设为UNVISITED,距离设为INFINIT。
2. 把出发点s的距离设置为0,状态设置为VISITED。
3. 从图中所有UNVISITED的点中选择距离最小的结点v。
4. 设置v的状态为VISITED。
5. 用v来更新其相邻结点。若某相邻结点u的当前距离D[u] > D[v] + weight(v, u),则把u的距离D[u]更新为D[v] + weight(v, u)。
6. 重复3到5步的操作,直到所有结点状态都被设置为VISITED。
以图1为例,算法的计算过程为:
1. D[A] = 0。
2. 选择D[A]为距离最小的结点,设其状态为VISITED;更新D = 10, D[C] = 3, D[D] = 20。
3. 选择D[C]为距离最小的结点,设其状态为VISITED;更新D[B] = D[C] + weight(C, B) = 3 + 2 = 5, D[E] = D[C] + weight(C, E) = 3 + 15 =18。
4. 选择D[B]为距离最小的结点,设其状态为VISITED;更新D[D] = D[B] + weight(B, D) = 5 + 5 = 10。
5. 选择D[D]为距离最小的结点,设其状态为VISITED;与D相连的结点E的距离D[E] = 18,小于D[D] + weight(D, E) = 10 + 11 = 21,所以不需要更新。
6. 选择D[D]为距离最小的结点,设其状态为VISITED;没有相连的点,所以不需要更新。
所以最终每个点的最小距离为D[A] = 0; D[B] = 5]; D[C] = 3]; D[D] = 10; D[E] = 18.
[b]2. 算法正确性证明
上一节描述的Dijkstra算法把图中的结点分为两个部分,分别标记为VISITED和UNVISITED,使用S和V-S来表示。为证明的方便,区分了S和V-S中的点的距离函数,分别为D和D_est,V-S中的距离函数被称为估值函数。算法的主要操作是循环执行第3到5步。证明算法的正确性,可以通过证明每次循环执行之前,S和V-S中的结点满足以下3条属性,执行之后依然满足。
属性1. S中任意m的点的的路径长度D[m]就是其最短路径。
属性2. 估值函数满足下述条件:
也就是说,对于V-S中的任意结点n,其估值路径D_est
是其只通过S中结点的最短路径。
属性3. V-S中估值最小的点n,D_est
的值就是其最短路径。
算法第一步S={s},只包含出发结点,且D[s]=0,故而满足属性1,更新相邻结点之后,容易证明,也满足属性2。属性3则需要证明,过程如下。
证明:假设D_est
不是n的最短路径,因为D_est是只通过S中结点的最短路径,所以结点n的真实的最短路径必然会经过集合S之外的结点,设路径上第一个非S中的点为j。则真实的最短路径的形式为s->...->j->...->n。因为假设了j之前的点都是S中的,所以根据属性2,D_est[j] < =D
< D_est
,与n是估值最小的结点矛盾,所以属性成立。
算法接下来的操作是把n加入S,并试图更新V-S中结点的距离估值,容易证明,3-5步的一次操作之后,属性1-3仍然满足,所以得证。
相关文章推荐
- 在数组中寻找主要元素的算法及其正确性证明。
- 迪杰斯特拉(Dijkstra)算法求解单源最短路径及其相应长度(java实现)
- 一道博弈的面试题及其算法正确性证明
- 判断一个正整数是否是2的N次方的简洁算法及其证明
- 数据结构-绪论-算法及其描述
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)
- 【HDU4313】Matrix 多校 解题报告+AC代码+思路+算法正确性证明,此为Kruskal贪心简单版本,恶心版本稍后放出【目标达成 0.2%】
- 最短路径算法—Dijkstra(迪杰斯特拉)算法分析与实现(C/C++)及其他 + leetcode习题实践
- HDU Today(迪杰斯特拉( Dijkstra)算法最短路)
- 数据结构之(图最短路径之)Dijkstra(迪杰斯特拉)算法
- 迪杰斯特拉(Dijkstra)算法 Java实现
- otsu自适应阈值分割的算法描述和opencv实现,及其在肤色检测中的应用
- 区间树中区间重叠检测算法正确性的证明
- 部分背包问题的贪心算法正确性证明
- 迪杰斯特拉(dijkstra)算法详解
- 迪杰斯特拉(dijkstra)算法详解
- Dijkstra(迪杰斯特拉)算法
- Java实现求最短路径算法——————Dijkstra(迪杰斯特拉)
- 手写matlab的迪杰斯特拉(dijkstra)算法的函数(注释很详细)
- 最短路径算法—Dijkstra(迪杰斯特拉)算法的实现(C++)