dijkstra算法主要用于求解图论算法中任意两点间的最短路问题,该算法维护了一个dist
数组,代表了每个点距离起点的距离,在开始时,dist数组中的元素应当全部为正无穷,且起点在dist数组中的值为0。该算法每次从距离起点距离未确定的点中找出一个距离起点最近的点,将其确定下来,并用该点距离起点的距离更新图中其他点与起点的最短距离。
注意: 当图中存在负权边时dijkstra算法无法保证正确性
dijkstra算法存在两种版本
普通版dijkstra
该版本每次在寻找距离起点最近的未确定的点时采用循环遍历整个数组的方式,时间复杂度为
O
(
n
2
)
O{(n^2)}
O(n2) 在稠密图中或者题目使用邻接矩阵时更加适用。
代码模板
int dijkstra(int start, int end)
{
memset(dist, 0x3f, sizeof dist);
dist[start] = 0;
for(int i = 1; i <= n; i ++ ) {
int t = -1;
for(int j = 1; j <= n; j ++ )
if(!st[j] && (dist[j] < dist[t] || t == -1))
t = j;
st[t] = true;
for(int j = 1; j <= n; j ++ )
dist[j] = min(dist[j], dist[t] + g[t][j]);
}
return dist[end];
}
堆优化版dijkstra
该版本采取将所有被更新过的点及其距离放入优先队列的策略,将确定最近未确定点的时间复杂度由
O
(
n
)
O(n)
O(n) 降低到了
O
(
l
o
g
n
)
O(logn)
O(logn) ,优先队列调整
O
(
l
o
g
n
)
O(logn)
O(logn),取最小
O
(
1
)
O(1)
O(1) ,更适合稀疏图,以及邻接表存图使用。
代码模板
int dijkstra(int Ts, int Te)
{
memset(dist, 0x3f, sizeof(dist));
dist[Ts] = 0;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>>q;
q.push({0, Ts});
while(!q.empty()){
int u = q.top().second;
q.pop();
for(int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
if(dist[j] > dist[u] + w[i]) {
dist[j] = dist[u] + w[i];
q.push({dist[j], j});
}
}
}
return dist[Te];
}
不难发现两种做法的区别在于从剩余点中取出最近点的策略,在实际做题中,题目大多给出两个点及其权值,使得第二种方法的使用更加普遍。