• 单源最短路(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

     #返回上一级

  • 相关阅读:
    生活记录-- 林微因《分手信》
    生活记录--林觉民《与妻书》
    生活记录--考研日记(1)
    SSO-单点登录(1)
    spring-注解----ext
    spring-注解----transaction
    spring-注解---aop
    spring-注解---autowired
    spring- 注解---values
    一样的Android,不一样的学习
  • 原文地址:https://www.cnblogs.com/zhanghaiba/p/3514570.html
Copyright © 2020-2023  润新知