• 迪杰斯特拉算法与佛洛依德算法


    迪杰斯特拉算法用于计算:某点v0到其他所有点的最短路径,时间复杂度为O(n^2)

    初态:

      设定V为所有顶点的集合。

      设定S为已经得到的最短路径的顶点vi的集合。即S中的顶点vi,都是已经确定下来v0到vi间的最短距离的顶点的集合。

      设定V-S为尚未计算得到最短路径的顶点集合。

      初态下,S为空,V-S=V。

      D[vi]为v0到vi的最短距离。

    基本思路:

      在V-S中,找一个顶点vi,该vi要满足:v0->vi间的距离,是V-S中v0到其他顶点vj的距离中最小的顶点。

      现在考虑v0->vi的最短路径,这个最短路径有三种可能:

      1).v0直接到vi

      2).v0到S中的某个或某多个顶点vk,在经由vk回到vi

      3).v0经过V-S中的某个或多个顶点vj,在经由vj回到vi.

      首先考虑3),这是不可能的。因为前提是v0->vi是V-S中最短的距离,如果说v0->vj->vi的距离是最短的,则v0->vj的距离一定小于v0->vi(因为v0->vi=v0->vj+vj->vi),而前提是假设v0->vi已经是V-S中最短的了,即v0->vj一定是大于v0->vi的,这与3)矛盾,因此只剩下1)和2)两种可能。

      因此,求v0->vi的最短距离,只要考虑1)与2)即可。

    基本流程:

      1).在V-S中找到一个满足v0->vi最短的顶点vi.

      2).更新v0经由vi到V-S中其他各点的最短距离,即如果k属于V-S且v0->vi->vk,则更新D[vk]=D[vi]+vi->vk。

    循环1)与2) n-1次后,任意点vi的D[vi]即为v0->vi的最短距离长度。

    不是问题的问题:

      看起来在基本流程的1)与2)的过程中,没有体现出基本思路中1)vo直接到vi与2)v0到S中的某个或某多个顶点vk,在经由vk回到vi间的比较,但实际上这个比较已经发生了。

    考虑正在计算v0->vi的最短路径,设定vk为计算v0->vi前的某个顶点,该顶点vk已经计算了v0->vk的最短距离并将加入到了S中。

    在计算vk的过程中,在进行到基本流程的2)时:

      此时开始更新v0经由vk到V-S中各点的距离,当遇到vi时,此时vi尚在V-S中,计算发现v0->vk->vi<v0->vi,则更新D[vi]=D[vk]+vk->vi。

      实际上在计算v0到vi的最短路径时,基本思路中1)与2)的对比是发生在vk的,在计算vk的第二个步骤中,发现v0->vk->vi的距离小于v0->vi,并更新了D[vi],也就是说,v0->vi和v0->经由S中的顶点->vi的距离谁更短这个问题已经在计算vi之前的顶点中发生了,当计算到vi时,此时的D[vi]已经代表了v0->vi和v0->经由S中的顶点->vi中的最小值。

    佛洛依德算法:

      用于计算每对顶点间的最短路径。其实使用迪杰斯特拉算法也可以达到每对顶点间的最短路径,只要对每个顶点均进行一次迪杰斯特拉,复杂度为O(n^3)。佛洛依德算法的复杂度也为O(n^3).

    基本思路:

      计算某两点vi到vj的距离时,首先考虑vi->vj的直接路径,这个路径(如果存在的话)可能是最短路径,也可能不是。

      现在在这两个路径间加入一个中间节点v0,变为vi->v0->vj,这个也可能是最短路径(如果存在的话),与上面的vi->vj对比一下,得到的路径就是在中间节点为v0下的最短路径。

      然后再往里加入一个节点vk,现在相当于有两个中间节点v0与vk了,vi经由v0与vk到vj的路径也可能是真正的最短路径。此时首先找出v0->vk间的最短路径,这个最短路径的中间节点目前只能有v0,或者没有,也就是对比vi->vk与vi->0->vk,得到的路径就是vi->vk的最短路径。同样对于vk->vj,在只用v0或不用的情况下,找出vk->vj的最短路径。然后将vi->vk与vk->vj这两个刚更新的最短路径加起来后与未加入vk前vi->vj间的最短路径作比较,最小的就是在中间节点为v0,vk的情况下的最短路径。

      循环上面的过程,知道所有中间节点都已加入。

      实际上这个过程就是,首先只有起点vi与终点vj,然后不断加入中间节点,计算得到在这些中间节点的情况下的最短路径,每次加入一个中间节点,都是相当于在不断逼近完整的图,在所有中间节点都已经加入后,这种情况已经是完整的图下求vi与vj间最短路径的问题了。

    基本流程:

      1).加入第idx个中间节点(初始情况下idx=0,也就是直接vi->vj)。

      2).在只使用前idx-1个中间节点的情况下,更新vi->vidx(vidx是刚加入的中间节点)与vidx->vj这两个顶点间的最短路径。

      3).将未加入第idx前vi->vj的最短路径与加入后vi->vidx+vidx->vj的距离进行对比,较小的作为加入第idx个中间节点的情况下vi到vj的最短距离。

    一点不是问题的问题:

    注意,如果说求的是整个图中任意两点间的最短距离,则在2)步中,通过两个for循环(严P191中v与w两个循环)已经更新了vi到任意某个尚未加入到图中的中间节点vm的距离与vm到vj的距离,这样当在将vm加入到图中时,D[vi][vm]和D[vm][vj]已经是最短的了。

    而如果求的是固定两个点vi和vj的最短距离,则在某个中间节点vz加入图中后,在进行到2)时,还要更新vi经由vz到所有尚未加入图的中间节点的距离,比如某个节点vk,这个节点要在vz后才加入,现在正在处理vz到2),此时比较vi->vk与vi->vk->vz的距离,更新D[vi][vk],这样当进行到加入vk时,D[vi][vk]就直接代表了vi到vk的最短距离。同理vk->vj也是如此,也是在计算vz的2)时,对比vk->vj与vk->vz->vj的距离,更新D[vk][vj],这样在加入vk到中间节点时,就能直接对比vk加入前的最短距离与D[vi][vk]+D[vk][vj]的大小。

  • 相关阅读:
    std::erase总结
    C++控制台应用程序运行控制台闪退
    判断当前进程是否已经打开C++
    获取当前系统语言C++
    VS中设置Qt多语言界面
    QString的功能
    安装mysql5.6
    centos6.9 PHP的编译安装并连接nginx
    centos6删除nginx
    centos6删除mysql安装
  • 原文地址:https://www.cnblogs.com/lxy-xf/p/11283695.html
Copyright © 2020-2023  润新知