用Dijkstra算法解决最短路问题
1.问题
对于下图使用Dijkstra算法求由顶点a到顶点h的最短路径。
![](https://img-blog.csdnimg.cn/20200309212135759.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQzNjMzMzUz,size_16,color_FFFFFF,t_70)
2.解析
若设1号点(a点)为起点,求长度为n的数组d,其中d[i]表示从起点到节点i的最短路径的长度。那么顶点a到顶点h的最短距离即为d[n]。
Dijkstra算法的流程如下:
- 初始化d[1]=0,其余节点的d数组的值为无穷大。
- 找出一个未被标记的、d[x]最小的节点x,然后标记节点x
- 扫描节点x的所有出边(x,y,z),若d[y]>d[x]+z,则使用d[x]+z,更新d[y]。
- 重复上述2,3两个步骤,直到所有节点都被标记。
Dijkstra算法基于贪心思想,它只适用于所有边的长度都为非负数的图。当边长z都是负数时,全局最小值不可能再被其他节点更新,故在之前选出的节点x必然满足:d[x]已经是起点到x的最短路径。我们不断选择全局最小值进行标记和扩展,最终可得到起点1到每个节点的最短路径的长度。
3.设计
void dijkstra(){
memset(d,0x3f,sizeof(d));
memset(v,0,sizeof(v));//节点标记
//默认起点为1号顶点
d[1]=0;
for(i form 1 to n-1){
int x=0;
//找到未标记节点中dist最小的
for(j form 1 to n){
if(!v[j]&&(x==0||d[j]<d[x])){
x=j;
}
}
v[x]=1;
//用全局最小值点x更新其他节点
for(y form 1 to n){
d[y]=min(d[y],d[x]+a[x][y]);
}
}
}
4.分析
时间复杂度分析:设n个顶点,m条边。
- 初始化d[1]=0,其余节点的d数组的值为无穷大:O(n)
- 找出一个未被标记的、d[x]最小的节点x,然后标记节点x,扫描节点x的所有出边(x,y,z),若d[y]>d[x]+z,则使用d[x]+z,更新d[y],不断重复该步骤,直到所有节点都被标记:O(n^2)
综上所述,Dijkstra算法的时间复杂度为O(n^2)。