1、问题分析:迪杰斯特拉算法是解决最短路径问题(即:两点之间的距离)
它于最小生成树的区别:
最小生成树是针对所有的点而言的算法,最小生成树的所有点的边权值加起来值最小,但是两个点之间的距离 ( 权值 ) 不一定是最小的。
迪杰斯特拉算法针对的是两个点之间的距离最短。
这道题的做题步骤是以 紧急救援 为例 而做的总结:
2、先输入题目给的信息:城市个数,城市的通道数,起点,终点,用一个数组(city)来保存每个城市的救援队的数量。
3、构建结构体,包含 v(通道能到达的城市) ,w (边权值),这里需要写重载函数(把 < 重载为 > , 原因就是优先队列默认是大根堆,我们需要将运算符重载,这样就变成小根堆了)。
4、使用邻接表构建图, 邻接表就是动态的二维数组( vector < node > a[ N ] ), a [ i ] 里面保存的是 i 城市分别可以到达的城市。
5、直接调用 dijkstra 函数:
(1)建立优先队列( priority_queue < node > q ),并将起点城市入队( q . push ( { s , 0 } ) )
(2)创建并初始化数组,需要一个记录到某个点的最小权值的数组( dis数组,初始化为 0x3f3f3f3f )和记录答案路径的数组( pre数组初始化为 -1 ).,还有记录救援队人数总和的数组(起点位置的救援总数为自己城市的救援数量),创建vis数组记录每个结点的为起点的情况,防止重复访问。
(3)当队列不为空的时候,取出队首并将队首pop()(优先队列的队首为 top ( ) ),将队首中的城市取出,判断这个城市有没有访问过,访问过就 continue ,没访问过就将这个城市标记为已经访问过。
(4)循环遍历 ( i ) 从这个城市能够到达的城市(a [ t ] . size ( ) ),j = a [ t ][ i ] . y 表示的是(从 t 这个城市到城市 y , i 是下标) ,a [ t ][ i ] . w 表示的是(从 t 这个城市到城市 y 需要的边权值, i 是下标)
(5)判断能否做松弛操作(即 if ( dis [ j ] > dis [ t ] + w ) ),
如果可以做松弛操作,就更新dis [ j ] 的值( dis [ j ] = dis [ t ] + w),就将 j 这个城市和 j 这个城市对应的最小权值( w )dis [ j ] 入队。
for(int i=0,l=a[t].size(); i<l; i++) {
int j=a[t][i].y,w=a[t][i].w;//j 是当前城市到达下一个城市的城市号码,w 是当前城市到达下一个城市的长度
if(dis[j]>dis[t]+w) {//松弛操作
dis[j]=dis[t]+w;
q.push({j,dis[j]});
sum[j]=sum[t]+city[j];
cnt[j]=cnt[t];
pre[j]=t;//记录上一个位置
} else if(dis[j]==dis[t]+w) {//如果路径长度相同,更新救援最大数量
cnt[j]+=cnt[t];
if(sum[j]<sum[t]+city[j]) {
sum[j]=sum[t]+city[j];
pre[j]=t;//更新当前结点的上一个位置
}
}
}
(6)写一个 print 函数将答案输出,可以定义一个栈 stack < int > S,将记录的路径输入栈里面,然后倒着输出,注意判断行末不能有空格。