简单介绍
- 上一篇提到了Bellman-Ford算法的另一种优化:每次仅对最短路程发生变化了的点的相邻边执行松弛操作
- 这一篇将用队列存储点,大致算法如下
讲解
- 用一个例子来详细说明
- 1号顶点为源点,用dis数组存储1号顶点到其余各个顶点的最短路径,初始时dis[1]=0,其余为∞,队列用一个数组que和head、tail指向队首和队尾
-
初始时将源点加入队列,每次从队首取出一个顶点,并对与其相邻的所有顶点进行松弛尝试,若某个相邻的顶点松弛成功且这个相邻的顶点不在队列中,则将它加到队列中,对当前顶点处理完毕后立即出队,并对下一个新队首进行如上操作直到队列为空,算法结束
-
可以用一个book数组来标记每个顶点是否处在队列中,但是注意这里的一个顶点很可能在出队列之后再次被放到队列中
-
也就是当一个顶点的最短路径估计值变小后,需要对其所有出边进行松弛,但是如果这个顶点的最短路程估计值再次变小,仍需要对其所有的出边再次进行松弛,这样才能保证相邻顶点的最短路程估计值同步更新
-
用队列优化的算法在于,可以降低其时间复杂度
-
松弛的顺序是按队列中的顺序来松弛的
- 下面来展示具体的松弛步骤
完整代码
#include<stdio.h>
#define MAX 999999
int main(){
int n,m,i,j,k,a;
//u,v,w数组的大小根据实际情况来设,要比m的最大值大1
int u[8],v[8],w[8];
//first,next数组的大小根据实际情况来设,first比n的最大值大1,next比m的最大值大1
int first[6],next[8];
//book数组用记录哪些点已经在队列中
int dis[6],book[6];
int que[101]={0},head=1,tail=1;
scanf("%d %d %d",&n,&m,&a);
//初始化dis数组
for(i=1;i<=n;i++)
dis[i]=MAX;
dis[a]=0;
//初始化book数组
for(i=1;i<=n;i++)
book[i]=0;
//初始化first数组为-1,表示暂时没有边
for(i=1;i<=n;i++)
first[i]=-1;
for(i=1;i<=m;i++){
scanf("%d %d %d",&u[i],&v[i],&w[i]);
next[i]=first[u[i]];
first[u[i]]=i;
}
//源点入队
que[tail]=a;
tail++;
book[a]=1;//标记源点已入队
while(head<tail){
k=first[que[head]];
while(k!=-1){
if(dis[v[k]]>dis[u[k]]+w[k]){
dis[v[k]]=dis[u[k]]+w[k];
if(book[v[k]]==0){
que[tail]=v[k];
tail++;
book[v[k]]=1;
}
}
k=next[k];
}
book[que[head]]=0;
head++;
}
for(i=1;i<=n;i++)
printf("%d ",dis[i]);
return 0;
}