Dijkstra 算法¶
Quote
迪杰斯特拉算法 (Dijkstra)是由荷兰计算机科学家狄克斯特拉于
引入¶
首先,我们一下就可以想到一个暴搜:我们用 BFS 搜索每一个点,然后往外拓展,如果发现了更优那么就进入队列。但是,这种算法的时间复杂度非常高,而且我们可以发现每一个点进入队列的时候其实当时的距离不一定是最优的,但是后面获得了更优的值,因此这一个点就会重复进入队列,然后再更新一遍,因此时间复杂度非常高。
算法思想¶
我们能够采取一些优化。对于非负权图,我们可以发现每一次的转移都是优不断转移到更劣的,因此我们只需要每一次都找到最优的状态,然后将这个点转移到后面,也就是更劣的状态。这里我们就利用了路径长度这个递增的拓扑序来求解了最短路问题,时间复杂度为
但是我们发现,其实没有必要每一次都花费
注意 STL 当中的优先队列如果更新了最短路的长度是,那么我们无法删除和更改以前的状态,因此队列的元素数量就变成了
注意
Dijkstra 只能处理正边权的最短路和负边权的最长路,如果在负边权中求最短路很有可能会死循环或求出错误的答案。如果想要求出负边权图的最短路,请转去隔壁看 Bellman-Ford 算法。
警告
在稠密图当中,
代码¶
朴素算法
void dijkstra(int s) {
fill(f + 1, f + n + 1, 1e9);
d[s] = 0;
for (int i = 1; i <= n; i++) {
int t = 0, mn = 1e9;
for (int j = 1; j <= n; j++) {
if (!f[j] && d[j] < mn) {
t = j, mn = d[j];
}
}
f[t] = 1;
for (auto j : e[t]) {
if (d[t] + j.v < d[j.to]) {
q.push(j.to, d[j.to] = d[t] + j.v);
}
}
}
}
使用优先队列优化
void dijkstra(int s) {
fill(d + 1, d + n + 1, 1e9);
for (q.emplace(s, 0), d[s] = 1; q.size(); q.pop()) {
Node t = q.top();
if (f[t.to]) {
continue;
}
f[t.to] = 1;
for (int i : e[t.to]) {
if (d[t.to] + i.v < d[i.to]) {
q.emplace(i.to, d[i.to] = d[t.to] + i.v);
}
}
}
}
-
来自百度百科,进行了一定处理。 ↩