# Dijkstra 算法
# 简介
迪杰斯特拉算法 (Dijkstra) 是由荷兰计算机科学家狄克斯特拉于 1959 年提出的,因此又叫狄克斯特拉算法。是从一个顶点到其余各顶点的最短路径算法,解决的是有权图中最短路径问题。迪杰斯特拉算法主要特点是从起始点开始,采用贪心算法的策略,每次遍历到始点距离最近且未访问过的顶点的邻接节点,直到扩展到终点为止。
Dijkstra 算法可用来求一个图中一个点到其他所有点的最短路径,时间复杂度为 O (n2),可优化为 O (nlogn)。
# 案例

如图,求源点 V1 到其它几个点的最短距离。
# 要点
int map[n+5][n+5] // 采用邻接链表的方式记录图信息  | |
int dis[n] // 用于存储源点到其它 n-1 个点的最短距离  | |
bool v[n] // 用于记录每个点的搜索状态,false 表示未搜  | 
从源点出发,每次找出 dis 中离源点最近的且未走过的点,替换出发点,更新 dis 的值。
# 算法详解
首先用邻接矩阵存储图信息,如下:
{  | |
{ 0, 8, 2, ∞, ∞, 5, ∞ },  | |
{ 8, 0, ∞, 2, ∞, ∞, ∞ },  | |
{ 2, ∞, 0, 3, ∞, ∞, 4 },  | |
{ ∞, 2, 3, 0, 4, ∞, ∞ },  | |
{ ∞, ∞, ∞, 4, 0, ∞, 2 },  | |
{ 5, ∞, ∞, ∞, ∞, 0, 2 },  | |
{ ∞, ∞, 4, ∞, 2, 2, 0 }  | |
 } | 
接着初始化 dis 数组,此时 dis[0, 8, 2, ∞, ∞, 5, ∞]
一开始 start = 1 ,令 v[1] = 1 表示 V1 点已搜;接着遍历 dis 数组,找出当前距离源点最近且未搜的点,这里为 V3 (距离为 2),令 start = 3 , v[3] = 1 ;然后更新 dis 数组 (当 dis[start] + map[start][i] < dis[i] 时,更新 dis[i] 的值),为 dis[0, 8, 2, 5, ∞, 5, 6] 。
重复上述步骤,依次如下:
start = 4 ,更新为 dis[0, 7, 2, 5, 9, 5, 6]start = 6 ,更新为 dis[0, 7, 2, 5, 9, 5, 6]start = 7 ,更新为 dis[0, 7, 2, 5, 8, 5, 6]start = 2 ,更新为 dis[0, 7, 2, 5, 8, 5, 6]start = 5 ,更新为 dis[0, 7, 2, 5, 8, 5, 6]
直到所有点都搜索过,此时 dis 数组即为源点 V1 到各个点的最短距离。
# 完整代码
#include <iostream> | |
#include <cstring> | |
using namespace std;  | |
//n 表示点的个数,m 表示边的个数,s 表示源点编号,这题为 1,mins 用于找出最小值 | |
int n, m, s, mins;  | |
int mp[10001][10001], dis[10001];  | |
bool v[10001];  | |
int main()  | |
{ | |
cin >> n >> m >> s;  | |
int a, b, c;  | |
memset(mp, 127, sizeof(mp));  | |
for(int i = 0; i < m; i ++){  | |
cin >> a >> b >> c; // 表示 a 到 b 有一条权值为 c 的边  | |
mp[a][b] = mp[b][a] = c; // 无向边  | |
    } | |
int t; // 记录当前未搜最近点  | |
for(int i = 1; i <= n; i ++) dis[i] = mp[s][i]; // 初始化 dis  | |
v[s] = 1; // 记录初始点已走  | |
dis[s] = 0; // 初始化,源点到源点自然是 0  | |
for(int k = 1; k <= n; k ++){  | |
mins = 0x7fffffff; // 令 mins 为极大值  | |
for(int i = 1; i <= n; i ++){ // 遍历找出当前距离源点最近且未搜的点  | |
if(!v[i] && dis[i] < mins){  | |
mins = dis[i];  | |
t = i; // 用 t 记下来  | |
            } | |
        } | |
v[t] = 1; // 记录 t 点搜索状态  | |
for(int i = 1; i <= n; i ++){ // 更新 dis  | |
if(mp[t][i] && !v[i] && dis[t]+mp[t][i] < dis[i])  | |
dis[i] = dis[t] + mp[t][i];  | |
        } | |
    } | |
    // 输出最终结果 | |
for(int i = 1; i <= n; i ++) cout << dis[i] << " ";  | |
return 0;  | |
} | 
# 案例测试
输入数据
7 9 1  | |
1 2 8  | |
1 3 2  | |
1 6 5  | |
2 4 2  | |
3 4 3  | |
3 7 4  | |
6 7 2  | |
4 5 4  | |
5 7 2  | 
输出结果
0 7 2 5 8 5 6  |