zoukankan      html  css  js  c++  java
  • 最短路

    本文介绍4种算法:SPFA, Dijkstra, Bellman-Ford, Floyd
    PS:文中分大小写。 图为G(V,E),V为节点集合,E为边集合,但v表示某个节点(v∈V)

    Dijkstra:

    • 原理:通过每一次解压节点min{key[v]|v∈G-已经生成的最短路径的树}并添加到树中,并将所有以v为起点的边松弛(key域),来达到最短路(贪心)
    • 注意:图中不能有负权,不能查是否有负权回路
    • 步骤:
      1. 初始化key域。每个key[v]=INF,v∈V
      2. 将最短路起点S的key[S] = 0
      3. 定义一个优先队列 priority_queue (#include <queue>) ,并将S节点(可以考虑用pair来绑定key域,也可以用一个结构来绑定)压入。//STL的队列默认为最大优先,故要创建一个比较类,重载()来实现最小堆
      4. 循环(直到队列为空)每一次解压最小值, 将最小key域所绑定的节点v解压出来并添加到树中(直接用一个bool数组来确定是否在树中即可,要输出路径就定义一个父亲域并维护)将v为起点的边全部松弛一遍,维护key域。并将这条边的终点压入队列。
    • 分析:时间复杂度O(N^2)
    • 适用于:稠密图
    • 优化:优化堆的实现,即手打FIB堆或其它比STL快的堆= =。可以达到O(NlogN)

    Bellman-Ford:

    • 原理:通过V-1次(最短路长度最多有V-1条边嘛- -)对每一条边松弛,来实现最短路(同样是贪心)
    • 好处:图中可以有负权,也能判断是否有负权回路
    • 步骤:
      1. 初始化key域。每个key[v]=INF,v∈V
      2. 循环(1~n-1)
      3. 枚举所有边进行松弛
      4. 判断是否有回路,循环(1~V)
        如果以v∈V为起点的边还能松弛,即有回路。(自己拿算导看证明哈,或者谷歌百度,或者自己想)
    • 分析:时间复杂度O(VE)
    • 适用于:稀疏图和负权图
    • 优化:我布吉岛

    Floyd:

    4行代码:

    for(k = 1; k <= N; k++)
    	for(i = 1; i <= N; i++)
    		for(j = 1; j <= N; j++)
    			node[i][j] = min(node[i][j], node[i][k]+node[k][j]);

    SPFA:(全名为:ShortestPathFasterAlgorithm)

    百科

    看到好文章,直接转过来了(点击打开链接

    我们知道,求一个图中的单源最短路径有Dijkstra、Ford这两种经典的算法。其复杂度均是O(N2),通过堆的优化,Dijkstra可以达到O(NlogN)的复杂度。但对于一些十分稀疏的图,这个复杂度就有些浪费了。当一个图中的边数e远远小于N2时,我们就考虑是否有一种算法,其时间复杂度只跟边数e有关系。于是SPFA诞生了。

    我们知道,Dijkstra的O(N2)是因为又一重循环是为了找到目前的Dist值最小的节点,于是我们想,能不能不找最小的,只是按照一定的顺序更新就可以了。那么算法的雏形就出来了,设S为源点:

    Quene←S
    While Quene not empty do
        Tmp←Quene
        For each node i with an edge to Tmp do
            If Dist[i] > Dist[Tmp]+length(edge(i,Tmp)) then
                Dist[i]←Dist[Tmp]+length(edge(i,Tmp))
                If i not in the Quene then
                    Quene←i

    这就是传说中的SPFA。我们来看看它的执行过程:

    为了图片的美观,我隐藏了顶点的标号。左上角的顶点为源点,黄的的点表示在队列中,绿色的点表示正在处理:

    至此,队列空,算法结束。

    为什么它能收敛呢?为什么它不会一直循环下去呢?因为总有一刻Dist[i]已经达到最小值,这时i这个顶点就再也不会入队了,并且当访问到i的时候,与i邻接的顶点也会被更新。所以总有一刻,所有的Dist都是最优值,算法结束。

    可以证明,假设每个节点的平均入队次数是k,那么时间复杂度就是O(ke)。而这里的k几乎可以认为是一个常数,所以简算之后时间复杂度为O(e)。

    如果时间复杂度优于这个值,就是说我们并没有处理完图中所有的边,就不可能一定可以得到最优解,所以,O(e)是所期望的最好的复杂度。
    PS:  有可能会更新,,欢迎大家吐槽

  • 相关阅读:
    虚拟主机导入MySQL出现Unknown character set: ‘utf8mb4’
    解决导入MySQL数据库提示"Unknown character set: 'utf8mb4'"错误
    在js中怎样获得checkbox里选中的多个值?
    CSharp设计模式读书笔记(0):设计原则(学习难度:★★☆☆☆,使用频率:★★★★★)
    how to install maven and svn plugin into eclipse 3.6
    三个月不编程,能力下降80%
    maven管理的struts2spring3mybatisfreemarker框架整合
    Wiki: JavaHL for subversion & ubuntu lucid
    重装系统要装的库包 for ubuntu lucid
    Q for Eclipse is an Apache Maven plugin for the Eclipse IDE
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/3521803.html
Copyright © 2011-2022 走看看