zoukankan      html  css  js  c++  java
  • Dijkstra算法——单源最短路径问题

    学习一个点到其余各个顶点的最短路径——单源最短路径

    Dijkstra算法是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有向图中最短路径问题。

    迪杰斯特拉算法主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

    算法的基本思想:

      每次找到离源点最近的一个顶点,然后以该顶点为中心进行扩展,最终得到源点到其余所有点的最短路径。

    算法基本步骤如下:

      1.将所有顶点分为两部分:已知最短路程的顶点集合P和未知最短路径的顶点集合Q。最开始,已知最短路径的顶点集合P中只有源点一个顶点。用一个book数组来记录哪些点                在集合P中。例如对于某个顶点i,如果book[i]为1则表示这个顶点在集合P中,如果book[i]为0则表示这个顶在集合Q中。

      2.设置源点s到自己的最短路径为0即dis[s]=0。若存在有源点能直接到达的顶点i,则把dis[i]设为e[s][i]。同时把所有其他(源点不能直接到达)顶点的最短路径设为无穷。

      3.在集合Q的所有顶点中选择一个离源点s最近的顶点u(即dis[u]最小)加入到集合P。并考察所有以点u为起点的边,对每一条边进行松弛操作。例如存在一条从u到v的边,那么可以通过将边u-->v添加到尾部来扩展一条从s到v的路径,这条路径的长度是dis[u]+e[u][v]。如果这个值比目前已知的dis[v]的值要小,我们可以用新值来替代当前dis[v]中的值。

      4.重复第三步,如果集合Q为空,算法结束。最终dis数组中的值就是源点到所有顶点的最短路径。

    应用:求下图中的1号顶点到2、3、4、5、6号顶点的最短路径

    e

    1

    2

    3

    4

    5

    6

    1

    0

    1

    12

    --

    --

    --

    2

    --

    0

    9

    3

    --

    --

    3

    --

    --

    0

    --

    5

    --

    4

    --

    --

    4

    0

    13

    15

    5

    --

    --

    --

    --

    0

    4

    6

    --

    --

    --

    --

    --

    --

     这里用二维数组e来存储顶点之间边的关系,初始值如上图。

    还需要一个一维数组dis来存储1号顶点到其余各顶点的初始路程。

    第一步:初始化dis数组

    第二步:找到了离1号最近的点2号,2号有两条边2->3和2->4。dis[2]+e[2][3]<dis[3],更新dis[3];dis[4]>dis[2]+e[2][4],更新dis[4]。

    第三步:当前离1号最近的是4号,对4号的三条边4->3,4->5,4->6进行松弛,更新dis数组。

    第四步:继续在3、5和6号中选择离1号最近的顶点,选择3号,对3号的所有出边3->5进行松弛,更新dis数组。

    第五步:在剩下的5和6号中选择离1号最近的顶点,选择5号,对5号的所有出边5->6进行松弛,更新dis数组。

    第六步:显然6号没有出边,所以dis数组中的所有值已经从“估计值”变成了“确定值”。

    实现代码如下:

    #include <stdio.h>
    
    int main()
    {
        int i, j, m, n;
        int q1, q2, q3;
        int u, v, min;
        int e[100][100], dis[10], book[10];
        int inf = 99999999;//用inf表示我们认为的无穷值
    
        scanf_s("%d %d", &n, &m);//读入n,m,n表示顶点个数,m表示边的条数
        //初始化
        for (i = 1; i <= n; ++i)
        {
            for (j = 1; j <= n; ++j)
            {
                if (i == j)
                {
                    e[i][j] = 0;
                }
                else
                {
                    e[i][j] = inf;
                }
            }
        }
    
        //读入边
        for (i = 1; i <= m; ++i)
        {
            scanf_s("%d %d %d", &q1, &q2, &q3);
            e[q1][q2] = q3;//有向图
        }
    
        //初始化dis数组,这里是1号顶点到其余各顶点的初始路程
        for (i = 1; i <= n; ++i)
        {
            dis[i] = e[1][i];
        }
    
        //book、数组初始化
        for (i = 1; i <= n; i++)
            book[i] = 0;
        book[1] = 1;         
        // Dijkstra 算法核心
        for (i = 1; i < n; ++i)      // 计算n-1次
        {
            //找到离1号顶点最近的顶点
            min = inf;
            for (j = 1; j <= n; ++j)
            {
                if (dis[j] < min && book[j] == 0)
                {
                    min = dis[j];
                    u = j;  //u为最近的点
                }
            }
            book[u] = 1;
    
            //对u的所有出边进行“松弛”
            for (v = 1; v <= n; ++v)
            {
                if (e[u][v] != inf && dis[v] > dis[u] + e[u][v])
                {
                    dis[v] = dis[u] + e[u][v];            //这个过程就是"松弛"
                }
            }
        }
    
        printf("结果为:
    ");
        //输出最终的结果
        for (i = 1; i <= n; ++i)
        {
            printf(" 1号顶点到%d号顶点的最短距离为:%d
    ",i, dis[i]);
        }
        printf("
    ");
    
        getchar();
        getchar();
        return 0;
    }

    调试结果如下图:

  • 相关阅读:
    记某app内购破解 – 安卓逆向菜鸟的初体验
    初探Android逆向:通过游戏APP破解引发的安全思考
    用IKVMC将jar转成dll供c#调用
    Java与.net 关于URL Encode 的区别
    RSA加密、解密、签名、验签的原理及方法
    C#使用SHA1加密类(RSAFromPkcs8)支持1024位和2048位私钥
    java与.net平台之间进行RSA加密验证
    RSA密钥,JAVA与.NET之间转换
    全面解决.Net与Java互通时的RSA加解密问题,使用PEM格式的密钥文件
    Android中Activity的启动模式(LaunchMode)和使用场景
  • 原文地址:https://www.cnblogs.com/lxt1105/p/6476379.html
Copyright © 2011-2022 走看看