问题描述:
给定若干城市以及各城市之间的路线,求出到达每个城市的最短路径。如下图所示,各字母代表城市,有边则代表城市之间连通,权值代表连通的城市之间的路径值。
图示:
Dijkstra求解:
1. Dijkstra思路分析
主要思想:通过构建的邻接矩阵,更新源点到所有顶点的路径。然后不断借助其他顶点更新源点到其他顶点的最短距离。
因此实现过程中,我们需要一个二维矩阵来保存各顶点间的连通关系。一个数组dist保存源点到达其他各顶点的距离。为了区别已经借助过的顶点和没有借助过的顶点,我们使用一个bool类型的数组保存各个顶点的使用关系。
2. 算法步骤
- 通过给定的各城市之间的连通关系,构建邻接矩阵(初始状态下,矩阵中各值为无穷大)
- 通过给定的源点,构建dist[]、p[]数组以及集合s和v-s(通过bool类型数组保存,若顶点在s中,则对应数组值赋为true)
- 在v-s中,寻找源点至其路径最短的顶点,并且将找到的顶点加入到s集合中
- 判断是否能借助上述找到的顶点,使到达其他顶点的路径最短
- 若存在这样的最短路径,则更新dist[]和p[]数组
- 直至v-s集合为空,表示已经找完了到达所有顶点的最短路径
代码示例:
#include<iostream>
using namespace std;
const int INT = 1e7;//定义无穷大
const int N = 100;
int n, m, s;//定义城市个数/城市之间连线条数和源顶点
int map[N][N], dist[N], p[N];
bool flag[N];
void init_map(int map[N][N]){
for(int i = 0; i < N; i++){
for(int j = 0; j < N; j++)
map[i][j] = INT;
}
}
void dijkstra(int s){
for(int i = 1; i <= n; i++){//先初始化dist、p和集合s
flag[i] = false;
dist[i] = map[s][i];
if(dist[i] != INT)
p[i] = s;
else
p[i] = -1;
}
flag[s] = true;
dist[s] = 0;
int t = -1, min;//查找最短路径
for(int i = 1; i <= n; i++){
min = INT;
for(int j = 1; j <= n; j++){
if(!flag[j] && dist[j] < min){//查找V-S中路径最小的顶点
min = dist[j];
t = j;
}
}
if(t == s) return;
flag[t] = true;
for(int j = 1; j <= n; j++){
if(!flag[j] && map[t][j] < INT){
if((dist[t] + map[t][j]) < dist[j]){
dist[j] = dist[t] + map[t][j];
p[j] = t;
}
}
}
}
}
int main(){
init_map(map);
cin >> n >> m >> s;//城市个数/城市间连线条数/源顶点
for(int i = 0; i < m; i++){//初始化邻接矩阵
int x, y, z;
cin >> x >> y >> z;
map[x][y] = z;
}
dijkstra(s);
for(int i = 1; i <= n; i++){
cout << "最短路径为:" << dist[i] << endl;
}
return 0;
}
结果输出:
参考文献:《趣味算法》