[Acwing算法基础] 3.4 Dijkstra算法

本文详细介绍了Dijkstra算法的原理和步骤,通过一个具体的Acwing849题目实例来展示其应用。使用邻接矩阵存储稠密图,算法在不存在负权边的图中寻找单源最短路径。文章提供了完整的C++代码实现,包括图的构建、最短路径搜索和距离更新。
摘要由CSDN通过智能技术生成

Dijkstra算法使用于单源最短路且不存在负权边的问题。时间复杂度为O(n^2)。Dijkstra算法的时间复杂度与图的边无关,所以适合于稠密图

在这里插入图片描述

本文以Acwing 849. Dijkstra求最短路I作为例子对Dijkstra算法进行说明

算法思想

Dijkstra 的整体思路比较清晰
即进行n(n为n的个数)次迭代去确定每个点到起点的最小值 最后输出的终点的即为我们要找的最短路的距离
所以按照这个思路除了存储图外我们还需要存储两个量

考虑下面地一个例子:
在这里插入图片描述
dijkstra详细步骤

  • 初始dist[1] = 0
  • 找到了未标识且离源点1最近的结点1,标记1号点,用1号点更新其他所有点的距离,2号点被更新成dist[2] = 23号点被更新成dist[3] = 5
  • 找到了未标识且离源点1最近的结点2,标识2号点,用2号点更新其他所有点的距离,4号点被更新成dist[4] = 4
  • 找到了未标识且离源点1最近的结点4,标识4号点,用4号点更新其他所有点的距离,5号点被更新成dist[5] = 5
  • 找到了未标识且离源点1最近的结点3,标识3号点,用3号点更新其他所有点的距离,4号点被更新成dist[4] = 3
  • 结束
  • 得到1号点到5号点的最短距离是5,对应的路径是1 -> 2 -> 4 -> 5,并不是真正的最短距离

1. 图的邻接矩阵存储

图的稠密图的保存使用一个二维数组保存。图的构建和保存的代码如下:

int g[N][N];    //为稠密阵所以用邻接矩阵存储

cin>>n>>m;
while(m--)
{
    int x,y,z;
    cin>>x>>y>>z;
    g[x][y]=min(g[x][y],z);     //如果发生重边的情况则保留最短的一条边
}

2. 找到剩余未确定的点中路径最短的点

为啥是这样等我的算法导论到了再看看吧

int t=-1;       //将t设置为-1 因为Dijkstra算法适用于不存在负权边的图
for(int j=1;j<=n;j++)
{
    if(!st[j]&&(t==-1||dist[t]>dist[j])    //该步骤即寻找还未确定最短路的点中路径最短的点
        t=j;
}

将该点标记为距离已确定

st[j] = true;

3. 使用刚刚找到的t更新其余未确定点的最短距离

这里j从1开始遍历是为了使代码更简洁,而且并不会改变已经确定的距离。

for(int j=1;j<=n;j++)
    dist[j]=min(dist[j],dist[t]+g[t][j]);

以上就是代码模板的主体部分。

完整代码

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=510;

int g[N][N];    //为稠密阵所以用邻接矩阵存储
int dist[N];    //用于记录每一个点距离第一个点的距离
bool st[N];     //用于记录该点的最短距离是否已经确定

int n,m;

int Dijkstra()
{
    memset(dist, 0x3f,sizeof dist);     //初始化距离  0x3f代表无限大

    dist[1]=0;  //第一个点到自身的距离为0

    for(int i=0;i<n;i++)      //有n个点所以要进行n次 迭代
    {
        int t=-1;       //t存储当前访问的点

        for(int j=1;j<=n;j++)   //这里的j代表的是从1号点开始
            if(!st[j]&&(t==-1||dist[t]>dist[j]))     
                t=j;

        st[t]=true;   

        for(int j=1;j<=n;j++)           //依次更新每个点所到相邻的点路径值
            dist[j]=min(dist[j],dist[t]+g[t][j]);
    }

    if(dist[n]==0x3f3f3f3f) return -1;  //如果第n个点路径为无穷大即不存在最低路径
    return dist[n];
}
int main()
{
    cin>>n>>m;

    memset(g,0x3f,sizeof g);    //初始化图 因为是求最短路径
                                //所以每个点初始为无限大

    while(m--)
    {
        int x,y,z;
        cin>>x>>y>>z;
        g[x][y]=min(g[x][y],z);     //如果发生重边的情况则保留最短的一条边
    }

    cout<<Dijkstra()<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东阳z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值