dijkstra算法

橙三吉。 提交于 2019-11-28 21:56:32

单源最短路算法Dijkstra

思路:每次寻找距离原点最近的点,通过该点松弛其他的点。

变量

 

m为边数,n为点数,dis[i]表示从1到点i的最短路径,book[i]表示点1到点i的路程是否最短,e为邻接矩阵,min和u之后才用到

 

int m, n, dis[N], book[N], e[N][N] min, u;

 

 

初始化+读入

 

读入n,m不再赘述

    scanf("%d %d", &n, &m);

 

一开始所有点都初始化为INF表示互不相连,i==j时自己连向自己,路程为0

   //初始化点i到j的距离为INF 自己到自己为0
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            if (i == j)
                e[i][j] = 0;
            else
                e[i][j] = INF;
        }

 

读入m条边 将数组e[a][b]的值赋值为权重c

    //读入
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        e[a][b] = c;
    }

 

因为e表示i到j的路程,dis表示从1到i的路程。

所以dis[i]初始化时等于e[1][i]

 就是 从1到i的路程 (dis[i]) 等于 从1到 i (e[1][i]) 的路程     翻译成人话就是完全一样的东西,但仅仅是初始化时

book数组0表示还未松弛,1表示松弛完毕即已经找到最短路径

book[1]表示点1到点1是否需要松弛,当然不用啊,所以book[1]=1;

    //初始化dis[i]为1到i的距离  顺便初始化book 1为已确定最短路 0为待松弛
    for (int i = 1; i <= n; i++) {
        dis[i] = e[1][i];
        book[i] = 0;//初始化所有点为待松弛
    }
    book[1] = 1;//自己不用松弛

 

算法思路

dijkstra主要分3步

1.找到目前距离1号点最近的点,记作点u

2.遍历点u联通的所有点,记作点v

3.如果从1直接到点v的距离 大于 从点1到点u再到点v的距离,更新1到v的最短距离

 

点1直接到点v的距离比从点u中转要大,所以要松弛点1到v的距离

如图  点1直接到点v的距离比从点u中转要大,所以要松弛点1到v的距离

 

 算法具体代码实现

1.找距离点1最近的点

 

先将最小值赋值为INF

min = INF;

 

先遍历所有点,如果这个点待松弛,即book[j]==0,并且是最小值,那我们更新最小值,然后用变量把最小点的编号记下来

        for (int j = 1; j <= n; j++) {            //遍历
            if (book[j] == 0 && dis[j] < min) {    //如果此点待松弛并且点1到点j的距离小于min
                min = dis[j];                    //更新min
                u = j;                            //更新离1号点最近的点的编号
            }
        }

 

2.遍历所有与点u相连的点

 

一个for循环搞定

for (int v = 1; v <= n; v++)

 

3.核心语句 松弛点1到点v的距离

        /****    如果目前离点1最近的点与点i联通(权小于INF)  并且  点1到点i的距离大于<点1到u再从u到i的距离>   ****/
            if (e[u][v]<INF && dis[v] > dis[u] + e[u][v]) {
                dis[v] = dis[u] + e[u][v];        //更新最小距离
            }

 

如果u和v不相连,那e[u][v]就是INF,下面这句是判断u和v是否相连

e[u][v]<INF

 

dis[v]表示1到点v的距离 下图1>>>v,dis[u]表示点1到点u的距离 下图1>>>u,e[u][v]表示点u到v的距离下图u>>v

dis[v] > dis[u] + e[u][v]

点1直接到点v的距离比从点u中转要大,所以要松弛点1到v的距离

所以这句话就是比较 1>>>v 和 1>>>u>>>v 那个小 ,我们求的是最短路,当然那个短要哪个。

 

dis[v] = dis[u] + e[u][v];        //更新最小距离

 

更新点 1>>>v 的值为 1>>>u>>>v

 

所以上面的代码翻译过来就是:

如果点u与点v相连,并且从点u中转比直接1到v要短。

  更新点1到v的距离为从点u中转的距离(之前要么是INF,即不相连,要么是点1直接到v的距离)

            if (e[u][v]<INF && dis[v] > dis[u] + e[u][v]) {
                dis[v] = dis[u] + e[u][v];        //更新最小距离
            }

 

 

然后这个点松弛完了我们要将他的book从0(未松弛)变成1(松弛完毕)

 

book[u] = 1;

 

 

以上是松弛了一个点,但我们要松弛所有点,就是找到所有点的最短路径。

我们一共有n个点,除去点1还有n-1个点,所以在外面套一个for循环就OK了

 

for (int a = 1; a <= n - 1; a++)//a在这就是个计数的

 

dijkstra算法代码如下

void dijksrat() {    

    for (int a = 1; a <= n - 1; a++) { //第一步
        min = INF;
        for (int j = 1; j <= n; j++) {
            if (book[j] == 0 && dis[j] < min) {   
                min = dis[j];                
                u = j;                           
            }
        }

        for (int v = 1; v <= n; v++) {           //第二步
       
            if (e[u][v]<INF && dis[v] > dis[u] + e[u][v]) {//第三步
                dis[v] = dis[u] + e[u][v];  
            }
        }
     book[u] = 1;//标记
    }
    return;
}

 

单源最短路算法完整代码:

//关闭VS安全检查#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstdio>
#define N 1001
#define INF 23333

int m, dis[N], book[N], e[N][N], n, min, u;

void dijksrat() {    

    for (int a = 1; a <= n - 1; a++) {            //将边松弛n-1次即可得到最短路径
        min = INF;
        //找到1号点最近的点
        for (int j = 1; j <= n; j++) {            //遍历
            if (book[j] == 0 && dis[j] < min) {    //如果此点待松弛并且点1到点j的距离小于min
                min = dis[j];                    //更新min
                u = j;                            //更新离1号点最近的点的编号
            }
        }

        for (int v = 1; v <= n; v++) {            //遍历所有点
        /****    如果目前离点1最近的点与点i联通(权小于INF)  并且  点1到点i的距离大于<点1到u再从u到i的距离>   ****/
            if (e[u][v]<INF && dis[v] > dis[u] + e[u][v]) {
                dis[v] = dis[u] + e[u][v];        //更新最小距离
            }
        }     book[u] = 1;
    }
    return;
}

int main()
{    
    scanf("%d %d", &n, &m);

    //初始化点i到j的距离为INF 自己到自己为0
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++) {
            if (i == j)
                e[i][j] = 0;
            else
                e[i][j] = INF;
        }

    //读入
    for (int i = 1; i <= m; i++) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        e[a][b] = c;
    }

    //初始化dis[i]为1到i的距离  顺便初始化book 1为已确定最短路 0为待松弛
    for (int i = 1; i <= n; i++) {
        dis[i] = e[1][i];
        book[i] = 0;//初始化所有点为待松弛
    }
    book[1] = 1;//自己不用松弛

    dijksrat();

    for (int i = 1; i <= n; i++)
        printf("%3d", dis[i]);
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!