Dijkstra

幻言

l  用来计算从一个点到其他所有点的最短路径的算法,是一种单源最短路径算法。 也就是说,只能计算起点只有一个的情况。

l  Dijkstra的时间复杂度是O (N2)(可优化为O(|E|log|V|)),它不能处理存在负 边权的情况。

 

算法描述:

l  设起点为s,dis[v]表示从s到v的最短路径,pre[v]为v的前驱节点,用来输出路径。

a)初始化:dis[v]=∞(v≠s); dis[s]=0; pre[s]=0;

b)For (i = 1; i <= n ; i++)

1.在没有被访问过的点中找一个顶点u使得dis[u]是最小的。

2.u标记为已确定最短路径

3.更新与u相连的每个未确定最短路径的顶点v

if (dis[u]+w[u][v] < dis[v]) {

dis[v] = dis[u] + w[u][v];

pre[v] = u;

}

  c)算法结束:dis[v]为s到v的最短距离;pre[v]为v的前驱节点,用来输出路径。

l  从起点到一个点的最短路径一定会经过至少一个“中转点”(例如下图1到5的 最短路径,中转点是2。特殊地,我们认为起点1也是一个“中转点”)。显而 易见,如果我们想求出起点到一个点的最短路径,那我们必然要先求出中转点 的最短路径(例如我们必须先求出点2 的最短路径后,才能求出从起点到5的 最短路径)。

 

 

l  换句话说,如果起点1到某一点V0的最短路径要经过中转点Vi,那么中转点Vi 一定是先于V0被确定了最短路径的点。

l  我们把点分为两类,一类是已确定最短路径的点,称为“白点” ,另一类是未 确定最短路径的点,称为“蓝点” 。如果我们要求出一个点的最短路径,就是 把这个点由蓝点变为白点。从起点到蓝点的最短路径上的中转点在这个时刻只 能是白点。

l  Dijkstra的算法思想,就是一开始将起点到起点的距离标记为0,而后进行n次 循环,每次找出一个到起点距离dis[u]最短的点u,将它从蓝点变为白点。随后 枚举所有的蓝点vi,如果以此白点为中转到达蓝点vi的路径dis[u]+w[u][vi]更短 的话,这将它作为vi的“更短路径”dis[vi](此时还不确定是不是vi的最短路 径)。

l  就这样,我们每找到一个白点,就尝试着用它修改其他所有的蓝点。中转点先 于终点变成白点,故每一个终点一定能够被它的最后一个中转点所修改,而求 得最短路径。

l  算法开始时,作为起点的dis[1] = 0,其他的点dis[i] = 0x7fffffff。

 

 

l  这时dis[2],dis[3],dis[4]被它的最后一个中转点1修改为了最短路径。

 

 

l  这时dis[3],dis[5]被它们的最后一个中转点2修改为了最短路径。

 

l Dijkstra无法处理边权为负的情况,如下图。

l  接下来的两轮循环将4、5也变成白点。N轮循环结束后,所有的点的最短路径 即能求出。

l  2到3的边权值为-4,显然从起点1到3的最短路径是-2(1→2→3),但是 dijskstra在第二轮循环开始时会找到当前dis[i]最小的点3,并标记它为白点。

l  这时的dis[3]=1,然而1却不是从起点到点3的最短路径。因为3已被标记为白点, 最短路径值dis[3]不会再被修改了,所以我们在边权存在负数的情况下得到了 错误的答案!

 

 

写法一

 

 

While每次将一个蓝点变成白 点,需要执行|V|次;红线部 分需要执行|V|次。所以时间 复杂度为o(n2).

写法二

 

 

邻接表存储,每次更新的同时将当前最 短距离和顶点的值对插入到堆中。时间 复杂度为O(|E|log|V|)。

|版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2018-03-26 20:56  沐雨雨  阅读(240)  评论(0编辑  收藏  举报