zoukankan      html  css  js  c++  java
  • 单源最短路(Dijkstra算法)

      #返回上一级

    @Author: 张海拔

    @Update: 2015-03-11

    @Link: http://www.cnblogs.com/zhanghaiba/p/3514570.html

    Dijkstra算法

    总的来说:算法从开始节点,按照总路径权值非递减的顺序去搜索所有路径,直到发现指定的终止节点或发现全部节点为止。

    ——我们先看看算法的步骤: 

    算法是递推的
    先设d[begin] = 0, d[others] = INF
    for [0, n)
    1、未标记的节点中,选出当前d值最小的 (最快logn效率)
    2、标记节点i
    3、据节点i,若d[i] + w[i][j] < d[j],则更新d[j](d[j]可能变小,O(n)效率)

    ——我们再看看为什么这样做

    循环每一步能确定以i节点为终点的最短路径(定义这种节点为:“最短路终点”)
    而且很关键的一点是,这个最短路径终点的d值是最小递增或者说一定是非递减的

    也就是上面说的“按照总路径权值非递减的顺序去搜索所有路径”

    另外,d值的意义是:当前状态下,以该节点为终点的最短路径长度

    假定A是起点,显然是A为终点的最短路径,d值是0

    后续步骤中都是从已确定最短路终点集合中,递推出下一个最短路终点

    想想最简单的情况
    A只能到B和C和D,AB边长5,AC边长3,AD边长4
    当前最短路终点集合只有A,集合一步可达的节点有B C D
    它们目前的d值分别是5 3 4
    把最小d值的C纳入最短路终点集合,因为它的d值无法变得更小,也就是说从当前状态往后这个节点的d值都是确定的

    为什么呢?
    把C纳入最短路终点集合,若CB边长是1,则会修改B的d值变为4,所以非最小值d值的节点,其d值可能会变得更小
    反过来,若纳入其它任何节点到最短路终点集合,都不可能使其d值变得更小
    因为不会出现 dNonMin + edge < dMin 的情况
    后续情况同理类推

    所以原理就是:

    根据已经最短路终点集合来递推下一个最短路终点

    过程使最短路终点集合一步可达的那些节点的d值不断减小

    直到某节点d值无法减小,则纳入最短路终点集合

    代码实现:

     1 /*
     2  *Author: ZhangHaiba
     3  *Date: 2014-1-10
     4  *File: dijkstra.c
     5  *
     6  *dijkstra's algorithm demo
     7  */
     8 
     9 #include <stdio.h>
    10 #include <string.h>
    11 #define N 512
    12 #define INF 0x7fffffff;
    13 
    14 void dijkstra(int, int);
    15 void print_path(int, int);
    16 void set_mat(int);
    17 void show_mat(int);
    18 
    19 int mat[N][N];
    20 int vis[N];
    21 int d[N];
    22 int par[N];
    23 
    24 int main(void)
    25 {
    26     int n;
    27 
    28     scanf("%d", &n);
    29     set_mat(n);
    30     //according to the question descript, begin=0, end=1
    31     int begin_v = 0, end_v = 1;
    32     
    33     dijkstra(begin_v, n);
    34     //print path: begin:0, end:par[1]
    35     print_path(begin_v, par[end_v]);
    36     printf("%d
    ", end_v);
    37     printf("%d
    ", d[end_v]);
    38     return 0;
    39 }
    40 
    41 void dijkstra(int begin, int n)
    42 {
    43     
    44     int t, i, min, x, y;
    45 
    46     //init
    47     memset(vis, 0, sizeof vis);
    48     for (i = 0; i < n; ++i)
    49         d[i] = INF;
    50     d[begin] = 0;
    51     par[begin] = begin;
    52 
    53     //loop n times
    54     for (t = 0; t < n; ++t) {
    55         //choice min d[i]
    56         min = INF;
    57         for (i = 0; i < n; ++i)
    58             if (!vis[i] && d[i] < min)
    59                 min = d[x = i];
    60 
    61         vis[x] = 1;
    62 
    63         //update
    64         for (y = 0; y < n; ++y)
    65             if (mat[x][y] > 0 && d[y] > d[x] + mat[x][y]) {
    66                 d[y] = d[x] + mat[x][y];
    67                 par[y] = x;
    68             }
    69     }
    70 }
    71 
    72 void print_path(int begin, int i)
    73 {
    74     if (i != begin)
    75         print_path(begin, par[i]);
    76     printf("%d ", i);
    77 }
    78 
    79 void set_mat(int n)
    80 {
    81     int i, j;
    82     
    83     for (i = 0; i < n; ++i)
    84         for (j = 0; j < n; ++j)
    85             scanf("%d", &mat[i][j]);
    86 }
    87 
    88 void show_mat(int n)
    89 {
    90     int i, j;
    91     
    92     for (i = 0; i < n; ++i)
    93         for (j = 0; j < n; ++j)
    94             printf(j == n-1 ? "%d
    " : "%d ", mat[i][j]);
    95 }

    测试用例

    输入:
    5
    0 100 0 30 10
    0 0 0 60 0
    0 10 0 0 0
    0 0 20 0 0
    0 0 50 0 0

    输出
    0 3 2 1
    60

     #返回上一级

  • 相关阅读:
    Oracle 推出 ODAC for Entity Framework 和 LINQ to Entities Beta版
    Entity Framework Feature CTP 5系列文章
    MonoDroid相关资源
    MSDN杂志上的Windows Phone相关文章
    微软学Android Market推出 Web Windows Phone Marketplace
    使用 Visual Studio Agent 2010 进行负载压力测试的安装指南
    MonoMac 1.0正式发布
    Shawn Wildermuth的《Architecting WP7 》系列文章
    使用.NET Mobile API即51Degrees.mobi检测UserAgent
    MongoDB 客户端 MongoVue
  • 原文地址:https://www.cnblogs.com/zhanghaiba/p/3514570.html
Copyright © 2011-2022 走看看