1. Dijstra算法求解的是有向图中一个顶点到其余顶点的最短路径
Dijkstra算法思想:设有两个顶点集合S和T,集合S中存放的图中已经找到最短路径的顶点,集合T中存放图中剩余顶点,初始状态的时候,集合S中只包含源点v0,然后不断从集合T中选取到顶点v0路径长度最短的顶点v并入到集合S中去,集合S每并入一个新的顶点,都要修改顶点v0到集合T中顶点的最短路径长度值
总结起来我感觉主要有两步:
① 选取源点到其余顶点路径最短的那个顶点
② 每选取一个顶点都要更新从源点到其余顶点的路径,因为每加入一个顶点,有可能使源点到其余顶点通过这个顶点的作用路径变得更短,比如源点0到3的路径一开始为4但是并入1节点之后那么路径为3变短了所以需要更新到3顶点的最短路径
2. 我感觉Dijkstra算法与Prim最小生成树的算法很类似,在编程方面上的区别:Prim算法中的d[]数组记录的是其余顶点到当前顶点的最短路径,而Dijkstra算法记录的是源点到其余顶点的最短路径,这个区别导致在更新d[]数组的时候的值也是不一样的,我们可以类比这两个算法来进一步理解其中的思想
下面是具体的有向有权的的一个例子:
假如以顶点0作为源点那么首先选取与顶点0相接的顶点,在循环中判断顶点0到相接的顶点的距离是否比之前源点到达这些顶点的路径是更短,可以发现路径是变短了,因为之前是没有路径到达1,3,4顶点的所以需要更新d[]数组中对应的三个顶点,下一次选取源点到达其余顶点中路径最短的,可以发现0到1顶点路径是最短的,所以选择1顶点,重复上面的步骤即可,可以发现1与3顶点相接,那么判断一下1顶点到3顶点的路径是否比之前源点到3的路径更短发现是变短了那么更新,以此类推其余顶点也是一样的道理
测试数据如下:
6 8 0
0 1 1
0 3 4
0 4 4
1 3 2
2 5 1
3 2 2
3 4 3
4 5 3
#include<cstdio>
#include<iostream>
using namespace std;
const int maxSize = 1000;
const int INF = 100000000;
int n, m, s, G[maxSize][maxSize];
int d[maxSize];
bool vis[maxSize] = {false};
void Dijkstra(int s){
fill(d, d + maxSize, INF);
d[s] = 0;
for(int i = 0; i < n; i++){
int u = -1, min = INF;
for(int j = 0; j < n; j++){
if(vis[j] == false && d[j] < min){
u = j;
min = d[j];
}
}
if(u == -1) return;
vis[u] = true;
for(int v = 0; v < n; v++){
if(vis[v] == false && G[u][v] != INF && d[u] + G[u][v] < d[v]){
d[v] = d[u] + G[u][v];
}
}
}
}
int main(void){
int u, v, w;
cin >> n >> m >> s;
//初始化二维数组
fill(G[0], G[0] + maxSize * maxSize, INF);
for(int i = 0; i < m; i++){
cin >> u >> v >> w;
G[u][v] = w;
}
Dijkstra(s);
for(int i = 0; i < n; i++){
cout << d[i] << " ";
}
}