关于最小路径的算法(Dijkstra算法)

来源:互联网 发布:中航工业津电 知乎 编辑:程序博客网 时间:2024/06/05 07:59

关于最小路径的算法(Dijkstra算法)

*注:这里我只研究算法,不研究实现* _(其实是本人太菜)

**先定义概念:Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他 *所有节点* 的最短路径(注意是可以求出到所有节点的最短路径)。**

主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。(我们通过对路线长度的计算,得到每个顶点的权重,权重越小,代表路径越短。)


需要两个集合来存储图中的顶点:

S集合初始只包含起始顶点,每算出来一条最短路径,就将新路径的终点加入集合中。

U集合为未确定最短路径的顶点的集合,初始包含图中除了初始顶点外的所有点。



    算法流程:

    ①->

      将初始点 v 存入 S 中,指定其权值为 0 ,设置 v 为中间点;
      将图中的除了v的所有点存入 U 中,暂时不指定它们的权值;

    ②->
      计算 :

     Q =  S中间点的权值  + S中间点到U中各点的距离; if( S中间点不和U中的点连接){     设置该点的 Q 为 无穷大; } //此时所有点都会有权值 if ( U中的各点还没有指定权值 ) {    指定该点的权值为 Q; } else ( U中的各点已经有了权值 ){     if ( Q < 该点的权值 ){        将该点的权值变为Q;    } else ( Q > 该点的权值 ){        不做动作;    } }


    ③->

      比较U中的所有点的权值,取出权值最小的那个点(这里暂时指定其为 k),将其放入S中,S就变为< v, k >, 此时将 k 设置为新的中间点 ,并且添加一条消息

      起点:v , 终点: k, 最短路径: v -> k

      每找到一条最短路径,就会更改中间点,并添加一条消息

    注意:这里需要留意一个问题:

    如果本次得到的最小权值并不是本次计算后更改的,而是之前求得的值,那么意味着v - k 再到某个点的距离 大于 v 直接到 某个点的距离,表述的不太清楚,这样看:

    这里写图片描述

    此时我们的图是这样的     v -> a       v -> b     a -> b第一次求最短路径     得到 v - b , S中是 < v , b >    此时,虽然a没有放入S中,但是它有了权值,正确的说,是V中所有点都有了权值。a的权值为 3, b的权值为2.第二次求最短路径    因为 Q = b->a的距离 + b 的权值  = 4  >  a的权值 Q= 3 (也就是第一次求得的权值),    所以 a 的权值不变。    因为 此时U中最小的权值不是本次计算后变化得到的,而是之前计算得到的权值    所以 本次求得的最短路径并不是 v -> b -> a 而是 v -> a    还是将权值最小的a放入S,并设置a 为新的中间点,并添加一条记录:        起始点: v ,目的地:a  ,最短路径: v -> a    如果是   Q = b->a的距离 + b 的权值   <  a的权值     将 a 的权值修改为 (b -> a的距离 + b 的权值),并将a放入X中,设置中间点为a,并添加一条记录:        起始点: v ,目的地:a  ,最短路径: v -> b -> a
    ④->
      转到②继续执行,直到U为空



    本人认为,如果要知道所有的最短路径,就得在每一次计算权重的时候,给这个顶点附加一条信息,来说明这次的权值是 哪几条路径 相加得到的。 
    比如:我们的附加信息为: a点的最短路径 = a之前的那条最短路径(用路径的终点表示) + a
    通过递归:
    a 之前的那条最短路径 = a 之前的之前的那条最短路径 + 之前的最短路径的终点 + a
    a 之前的之前的那条最短路径 = a 之前的之前的之前的那条最短路径 + 之前的之前的最短路径的终点 + a

    直到找到起点
    然后我们就能找到每条最短路径啦

    阅读全文
    0 0