zoukankan      html  css  js  c++  java
  • 最短路径算法 2.Dijkstra算法

    Dijkstra 算法解决的是带权重的有向图上单源最短路径问题,该算法要求所有边的权重都为非负值。该算法的时间复杂度是O(N2),相比于处理无负权的图时,比Bellmad-Ford算法效率更高。

    算法描述:

    首先引用《算法导论》中的一段比较官方的话,如果可以看懂,那下一部分就可以跳过了:

    “Dijkstra算法在运行过程中维持的关键信息是一组结点集合S。从源结点s到该集合中每个结点之间的最短路径已经被找到。算法重复从结点集 V - S 中算则最短路径估计的最小的结点 u ,将 u 加入到集合S,然后对所有从 u 出发的边进行松弛。” 所谓松弛操作,简单的说就是更新两点间的最短距离。

    不是很好理解对吧,那么下面的描述是更容易理解的一种描述:

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

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

    2、for(i=1;i<=n;i++)

    (1)在没有被访问过的点中,即上述的V - S集合,找到一个点 u 使得dis[u]是最小的。

    (2)标记 u 为已确定的最短路径。

    (3)for(每个与 u 相连且没有确定过最短距离的点 v)     

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

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

      pre[v]=u;

    }

    3、结束:结果dis[v]就是s到v的最短距离。

    算法理解:

    其中自以为有几点理解需要说明:

    1、为什么用到中间点?

    2、取s到中间点的距离时采用什么策略?

    第一个问题,从起点到另一个点的最短路径至少会经历一个中间点,所以我们要求出经过这个中间的到另一个点的路径,就要先求出起点到中间点的最短路径。

    第二个问题,其实这里采用的是一中贪心的策略。当然这个策略可以被严格证明是正确的,但是我也一知半解,只知道是可以被证明的,在这里也就不浪费时间了。(详细可以参考《算法导论》)

    最后,解释一下为什么有负权边的时候不可以:

    连接矩阵如下(图可以自己在旁边画一下):

      1 2 3

    1 2 1

    2 2 -4

    3 1 -4

    那么第一次标记的点就为3并且把dis[3]记为1,但实际上dis[3]应该时-2,因此就会出现错误。

    最后附上一段不那么标准的代码:

     1 #include<stdio.h>
     2 #include<stdlib.h>
     3 int m[100][100],e,dist[100],n,b[100],pre[100],dist[100];
     4 void dij(int s){
     5      b[s]=1;
     6      int i,j;
     7      for(i=1;i<=n;i++)
     8       dist[i]=m[s][i];
     9      dist[s]=0;
    10      pre[s]=0;
    11      
    12      for(i=1;i<=n;i++){
    13       int min=1000000,k=0;
    14       for(j=1;j<=n;j++)
    15        if(b[j]!=1 && dist[j]<min)
    16         {min=dist[j];k=j;}
    17        b[k]=1;
    18        for(j=1;j<=n;j++)
    19         if(min+m[k][j]<dist[j]&&b[j]!=1)
    20          {
    21           dist[j]=min+m[k][j];
    22           pre[j]=i;
    23           }                                
    24       }
    25       for(i=1;i<=n;i++)
    26        if(i!=s)
    27         printf("%d ",dist[i]);
    28      }
    29 int main(){
    30     int i,j;
    31     scanf("%d%d",&n,&e);
    32     memset(b,0,sizeof(b));
    33     memset(m,10000,sizeof(m));
    34     for(i=1;i<=e;i++){
    35      int x,y;
    36      scanf("%d%d",&x,&y);
    37      scanf("%d",&m[x][y]);
    38      }
    39     int w;
    40     scanf("%d",&w);
    41     dij(w);
    42     system("pause");
    43     return 0;
    44     }
  • 相关阅读:
    go案例:客户管理系统流程 mvc模式 分层设计
    珠峰2016,第9期 vue.js 笔记部份
    前后端分离电商,业务逻辑部份
    'Specifying a namespace in include() without providing an app_name '报错解决
    vue2.0 前端框架
    vue项目实战
    电商网前后端分离数据表设计部份
    djang2.1教育平台02
    django框架开发流程
    测试的艺术:测试用例的设计
  • 原文地址:https://www.cnblogs.com/uncklesam7/p/8831204.html
Copyright © 2011-2022 走看看