Dijkstra算法

Dijkstra算法

1.最短路问题

在图论中,最短路问题分为单源最短路和多源最短路。

其中,单源最短路又分为存在负权边和不存在负权边两种。

Dijkstra算法就是来解决不存在负权边的最短路问题的。

2.Dijkstra算法思想

如果图是不带负权的有向图或者无向图,从起点 \(v0\) 每次新扩展一个距离最短的点,再以这个点为中间点,更新起点到其他所有点的距离。

由于所有边权都为正,故不会存在一个距离更短的没被扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。

3.Dijkstra算法步骤

①初始化 \(d[v0]=0\),源点到其他点的距离值 \(d[i]=∞\)

②经过 \(n\) 次如下步骤操作,最后得到 \(v0\)\(n\) 个顶点的最短距离:

A.选择一个未标记的点 \(k\) 并且 \(d[k]\) 的值是最小的;

B.标记点 \(k\),即 \(f[k]=1\)

C.以 \(k\) 为中间点,修改源点 \(v0\) 到其他未标记点 \(j\) 的距离值\(d[j]\)

解释:

\(f[i]\):值为\(true\),已求得最短距离,在集合1中;

值为\(false\),在集合2中。

开始点(源点):\(v0\)

\(d[i]\):顶点 \(v0\)\(i\) 的最短距离。

初始:
\(d[v0]=0\)\(d[i]=a[v0][i]\)

这些的代码实现

memset(d,0x3f,sizeof(d));//初始化为正无穷
d[1]=0;
for(int i=1;i<=n;i++){//核心代码 
    int k=-1;
    for(int j=1;j<=n;j++)
    if(!f[j]&&(k==-1||d[k]>d[j]))//如果点j没有确定最短路且k还没有被赋值或它不是最短的 
        k=j; 
    f[k]=true;//确定k点最短路 
    for(int j=1;j<=n;j++)
       d[j]=min(d[j],d[k]+g[k][j]);//比较原始j的最短路和新路大小并赋值 
}

算法的时间复杂度为 \(O(n^2)\),因为每次寻找未标记的结点需要耗时 \(O(n)\),可以用堆优化此处,时间复杂度降为 \(O(mlogn)\)

4.代码实现

#include<iostream>
#include<cstring>
using namespace std;
const int N=505;
int n,m;//n个点,m条边 
int g[N][N];//邻接矩阵存储 
int d[N];//1号点到任意点的距离 
bool f[N];//有没有确定最短路
int dij(){//Dijkstra算法 
    memset(d,0x3f,sizeof(d));//初始化为正无穷
    d[1]=0;
    for(int i=1;i<=n;i++){//核心代码 
        int k=-1;
        for(int j=1;j<=n;j++)
            if(!f[j]&&(k==-1||d[k]>d[j]))//如果点j没有确定最短路且k还没有被赋值或它不是最短的 
                k=j; 
        f[k]=true;//确定k点最短路 
        for(int j=1;j<=n;j++)
            d[j]=min(d[j],d[k]+g[k][j]);//比较原始j的最短路和新路大小并赋值 
    }
    if(d[n]==0x3f3f3f3f) return -1;
    else return d[n];
}
int main(){
    cin>>n>>m; 
    memset(g,0x3f,sizeof(g));//初始化为正无穷 
    for(int i=1;i<=m;i++){
        int x,y,z;// x到 y的有向边,长度为z 
        cin>>x>>y>>z;
        g[x][y]=min(g[x][y],z);//在x到y的边中取最小的值 
    }
    cout<<dij();
    return 0;
}

注释已全部标出,不理解可以多看几遍。

完awa~

不多不少90行。

如果觉得还不错就点个赞吧,您的支持就是本蒟蒻最大的动力。

posted @ 2022-07-18 13:08  Rainforests  阅读(185)  评论(0编辑  收藏  举报