最短路径之Dijkstra算法

本文详细介绍了Dijkstra算法解决有向加权图最短路径问题的过程。该算法适用于所有边权非负的情况,通过逐步更新距离并标记已确定最短路径的顶点来找到从源点到所有其他顶点的最短路径。
1.解决问题

有向加权图的最短路径问题。

2.算法条件

该图所有边的权值非负,即对于每条边(u,v) ∈ E , w(u,v) ≥ 0。

3.模拟算法运行过程

图

Dijkstra算法中,主要采用了dis[N]数组,记录点到源点的最短距离,以及visit[N]数组,主要用来记录该点是否在集合中(代码中是根据visit[i] == true 或者 visit[i] == false来判断的)。
我多用了一个path[N]数组来记录最短路的路径,初始化为自己的下标。
从1号节点开始,将其相邻的边的权值记录到dis数组中,并且将1号节点的visit状态置为true:
这里写图片描述
1号节点到2号节点以及4号节点的权值记录在dis数组中,并且对path路径进行刷新path[2]=1,path[4]=1
挑选dis数组里面visit值为false且值最小的点,在上面的状态便是挑选2号节点,因为v1–>v2一定是(v1,v2)的最短路,不可能经过第三个点进行转折,这是因为1号节点到其他点的距离均大于v1–>v2的距离。我们把v2的visit状态置为true:
这里写图片描述

下面,从2号节点开始,将其相邻的边的权值之和与原值进行对比,取小的,记录到dis数组中,同时更新path数组,并且再次选择dis数组里面visit状态为false且值最小的点。因为(v1–>v2–>v4) =18 > (v1 -->v4) = 10,所以不更新dis[4]和path[4]的值。此次选择的是5号节点,将五号节点的visit值置为true:
这里写图片描述

下面,从五号节点开始,将其相邻的边的权值之和与原值进行对比,取小的,记录到dis数组中,同时更新path数组,并且再次选择dis数组里面visit状态为false且值最小的点。因为(v1–>v5–>v3) =19 > (v1 -->v2 -->v3) = 17,所以不更新dis[3]和path[3]的值。此次我们选择4号节点,将4号节点visit值置为true:
这里写图片描述

最后dis数组里面visit值为false且值最小的点就是3号节点,所以在选择3号节点,并将其visit状态置为true:
这里写图片描述

算法执行结束。

4.算法核心代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 1000;
const int INT_MAX = 0x3f3f3f3f;
int e[N][N];//存边,e[i][j] == -1 表示(i,j)之间不存在边 
int dis[N];//求最短路的状态数组
bool vis[N];//将已经求得最短路的点状态置为true
int path[N];//用来记录最短路的路径
int n , m; //n --> 点的个数 , m --> 边的个数

//dijkstra算法:start-->最短路起点

void dijkstra(int start){
    dis[start] = 0;
    int cnt = 0;
    path[1] = 0;
    while(cnt < n){
        int temp = INT_MAX;
        int tempIndex;
        for(int i = 1;i <= n;i++){
            if(!vis[i] && temp > dis[i]){
                temp = dis[i];
                tempIndex = i;
            }
        }
        vis[tempIndex] = true;
        cnt++;
        //更新tempIndex到其他未访问的点的最短路径
        for(int i = 1;i <= n;i++){
            if(!vis[i] && e[tempIndex][i] != -1 && dis[i] > dis[tempIndex] + e[tempIndex][i]){   
                dis[i] = dis[tempIndex] + e[tempIndex][i];
                path[i] = tempIndex;      
            }
        }
    }
}

int main(){
    memset(e , -1 , sizeof(e));
    memset(dis , 0x3f , sizeof(dis));
    memset(vis , false , sizeof(vis));
    int from , to , cost;
    cin >> n >> m;
    for(int i = 0;i < m;i++){
        cin >> from >> to >> cost;
        e[from][to] = cost;
    }
    dijkstra(1);
    for(int i = 1;i <= n;i++){
        cout << dis[i] << " " ;
    }
    cout << endl;
    return 0;
}
5.最短路径例题

见博客:CodeVS 1021 玛丽卡——最短路问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值