转载请注明出处https://blog.csdn.net/bestsort
Dijkstra 使用的是贪心的思想,先假设所有顶点之间都没有边相连,然后每次从输入的边中选取一条权值最小的边并连接该边所对应的两个顶点,直到最后所有的顶点都被连通为止(即所有的顶点都能通过某一路径走到指定的点),如下图;
以顶点(1)为起点,点(1)连通有(6),(3),(2)三个点,权值分别为14,9,7(其他点赋值为无穷大);
所以选择权值最小的7,并连接(1,2)这条边(这里是通过并查集把两个点并入同一个祖先实现的)
然后再次遍历存权值的数组,找出下一个没被使用过且权值最小的边,并入集合中,这样一直循环n-1次,遍历了n-1个顶点之后,dis[j]就为从起点a->j的最短距离。
算法时间复杂度为O(n^2) (可以用堆或者优先队列优化达到更低的时间复杂度,可是我不会= =.....)
GIF图解如下:
所以每次需要执行的就是-
->找一条没有被标记且权值最小的边
->将该边所连的顶点标记
->将记录距离的数组更新
->重复第一步
需要注意的是,一开始设距离为无穷大,如果一圈找完后还是存在距离=无穷大,那么说明剩下的顶点与集合内的顶点均不连通.
再附一张Dijkstra算法应用的示意图(wiki盗的~)
起点以左下角的红点
目标是右上角的绿点
中间灰色的倒L型为障碍物
蓝色空圈表示"暂定",用以搜索下一步;已经填充颜色的表示探访过,图中颜色以红到绿,越绿表示离起点越远。所有节点都被均匀的探索。
代码初学时可能看着比较难以理解,但是自己试着抄一下,每一行每一行的看下来会发现还是很好理解的
以下是代码模板
#include
#include
#include
#include
#define mem(a,b) memset(a,b,sizeof(a))
#define For(a,b) for(int a=0;a (dis[Np]+map[Np][j])){
dis[j] = dis[Np]+map[Np][j];
pre[j] = Np;
}
}
}
int main()
{
int a,b,c;
while(cin >> n>>m){
For(i,m){
cin >> a >> b >> c;
map[a][b] = map[b][a] = min(map[a][b],c);
}
dijkstra(1);
cout << (dis[n]==INF?-1:dis[n]) << endl; ///1->n的最短路
}
return 0;
}