迪杰斯特拉算法

迪杰斯特拉算法(单源最短路径)

算法基本流程:node 0 as start. 注意算法流程默认图是联通的,若不联通,需要添加循环跳出处理。

image-20230805163622438

step Node 0 Node 1 Node 2 Node 3 visited point set
0 ( init ) 0 INT_MAX INT_MAX INT_MAX {}
1 0 (√) 3 1 INT_MAX {{0}}
2 0 (√) 3 1 (√) 9 {{0, 2}}
3 0 (√) 3(√) 1 (√) 9 {{0, 2, 1}}
4 0 (√) 3(√) 1 (√) 9(√) {{0, 2, 1, 3}}

注意步骤是:先找点加入visited set, 再更新距离。

循环次数即为点的个数。

step0:初始化,除了起点本身距离为0,到其余点的距离均为INT_MAX,且目前所有点均未被访问;

step1:找到起点距离最近的点为本身node:0,将node 0加入visited set,,再计算从点0出发的到未访问点的新距离是否可以更小;

如在step2时,新加入了点2,从点2出发查找所有未访问的点{1, 3},于是发现dis(0-->1) = dis(0-->2) + dis(2-->1) = 3,不更新;

dis(0-->3) = INT_MAX, dis(0-->2) + dis(2-->3) = 9, 后者小于前者,于是更新dis(0-->3) = 9;

以下步骤相同,不再赘述。

伪代码表述:

Init the distance vector as INT_MAX;
Set distance[start]=0;
Init the visited vector as False;

For step in (0, n-1):
	# 每次访问一个点,这个点是距离start最近的点,将其加入现在已经访问的节点集合中
	minP, minD;
	For point in points_all:
		If(point not visited and minD > distance[point]):
			minP = point;
			minD = distance[point];
	# 找到最近的点后,根据这个节点更新目前的可访问距离
	Find point with minium distance in unvisited point set;
	Update distance vector.

实际代码:

#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
#define M INT_MAX
ostream& operator<<(ostream& os, vector<int>& dis) {

    for(int d : dis){
        os<<d<<" ";
    }
    return os;
}
int main(){
    int n=4; // 节点数量
    vector<int> visited(n, 0); // 访问标记
    vector<vector<int>> map={{0, 3, 1, M},
                             {3, 0, 2, 10},
                             {1, 2, 0, 8},
                             {M, 10, 8, 0},}; // 每两个点之间的距离二维矩阵
    vector<int> distance(n, M);
    int start = 0;
    distance[start] = 0;
    int count = 0;
    while(count++ < n){
        // 找一个距离start最近的未访问点添加到已经访问节点中
        int minPoint, minDis = INT_MAX;
        for(int i=0; i<n; i++){
            if(!visited[i] && minDis > distance[i]){
                minDis = distance[i];
                minPoint = i;
            }
        }
        visited[minPoint] = 1;
        // 更新距离列表
        for(int j=0; j<n; j++){
            if(map[minPoint][j] != INT_MAX && map[minPoint][j] + distance[minPoint] < distance[j]){
                // 这个地方为了防止int溢出,也可以用减号:distance[j]-distance[minPoint] > map[][]
                distance[j] = map[minPoint][j] + distance[minPoint];
            }
        }
    }
    cout<<distance<<endl;
}

此处代码实现其实有些累赘,可以使用unordered_set类型来分别保存已访问的节点和未访问的节点,这样就不必遍历所有的节点了。

posted @ 2023-08-05 17:03  石中火本火  阅读(89)  评论(0编辑  收藏  举报