前言
这几次面试的确有好多次问到了最短路径算法,当时答得确实不好,对算法理解的不是很透彻,下面简单梳理一下。
Dijkstra算法
Dijkstra算法有点DP的意思,适用于单源最短路径算法且要求边的权值非负,同时可以用于有向图和无向图。
数据结构定义:
map[][]
:存放原始图;dis[]
:存放从源点出发到达点i的最短路径长度;visited[]
:记录节点是否已被访问。
初始化:dis[i] = map[0][i]
,从源点出发到达各点的距离,无法到达记为INT_MAX;visited(map.size(), 0), visited[0] = 1
,初始只访问过源点。
思想:
双集合的说法可以查到很多,也解释的很详细,这里说一下我的理解。记源点为A。
- 遍历dis数组(一共做n-1次),找到目前从源点出发,到达未访问节点
i
的最短路径; - 更新visited数组,置
visited[i] = 1
; - 更新目前源点经由
i
中转到未访问节点的最短路径(假设i=B
),如A->B->C
,C为一未访问节点。这里的目前是指现在只能保证A->B
的路径最短,更新得到的A->B->C
路径只能保证现在是最短的。
但是绝不可能有经过某一节点j
中转到达i
的路径比这一步找到的路径短,因为后面找到的可以从源点A到达的未访问点(假设目前找到了A->B
,存在B<->C,
):- 要么本来A可以访问到C;存在
A->C
,则有A->C->B
,如果A->C->B
的路径短于A->B
,则必有A->C
的路径短于A->B
的路径,那么这一步找到的最短路径便是A->C
,不会是A->B
; - 要么本来A访问不到C;此时访问到C,只有
A->B->C
,假如有一条路径可以经过C和其他节点到达B,如A->B->C->D->B
,因为到达C首先已经经过了B,在经由C中转到达B的路径必包含A->B->C
,这种情况不可能发生。
- 要么本来A可以访问到C;存在
- 重复上述过程n-1次,即可找到从源点出发到达任意节点的最短路径。
参考代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> Dijkstra(vector<vector<int>> &map);
int main(int argc, char *argv[]) {
const int M = INT_MAX;
vector<vector<int>> map
{
{
0,6,3,M,M,M},
{
6,0,2,5,M,M},
{
3,2,0,3,4,M},
{