最短路算法之:Dijkstra 算法
最短路系列:Dijkstra 算法
大家好,我是Weekoder!
最短路系列的第二期:Dijkstra 他来啦!
那么废话不多说,让我们直奔主题吧。
Dijkstra 算法的用处
与 floyd 算法不同的,Dijkstra 算法用于求解单源最短路径。顾名思义,单源最短路径就是起点唯一,终点有多个的最短路算法。
Dijkstra 的思想是贪心,而这也将在算法的实现步骤中体现出来。
DIjkstra 算法的思想
Dijkstra 算法是以点为研究对象的最短路算法。我们把图中的点分为两种:黑点和白点。黑点是已经找到最短路的点,白点则相反。一开始所有点都是白点,我们需要将这些点全部染成黑点。用一个
我们有一个
而其余的则设为 INF(
我们每次在
如此往复,直到所有点染成黑色。
Dijkstra 算法的正确性
刚才说到 Dijkstra 是将所有点染成黑色,每次找
和
Dijkstra 的实现
根据我们上面的逻辑写即可。这份代码仅能通过P3371。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e4 + 5;
struct Edge {
int to, dis;
};
ll n, m, s, dis[N];
bool vis[N];
vector<Edge> nbr[N];
void dijkstra() {
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
for (int i = 1; i <= n; i++) {
ll minx = 1e18, x;
for (int j = 1; j <= n; j++)
if (!vis[j] && dis[j] < minx)
minx = dis[j], x = j;
vis[x] = 1;
for (Edge nxt : nbr[x]) {
ll to = nxt.to, w = nxt.dis;
dis[to] = min(dis[to], dis[x] + w);
}
}
}
int main() {
cin >> n >> m >> s;
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
nbr[u].emplace_back((Edge){v, w});
}
dijkstra();
for (int i = 1; i <= n; i++)
cout << (dis[i] == 0x3f3f3f3f3f3f3f3f ? (ll)pow(2, 31) - 1 : dis[i]) << " ";
return 0;
}
容易发现,Dijkstra 算法的时间复杂度是
Dijkstra 算法的优化
考虑优化 Dijkstra 的时间复杂度。对于第一层大循环的
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
struct Edge {
int to, dis;
};
struct node {
int y, w;
bool operator<(const node &x)const {
return w > x.w;
}
};
int n, m, dis[N];
bool vis[N];
vector<Edge> nbr[N];
priority_queue<node> q;
void dijkstra(int s) {
memset(vis, 0, sizeof vis);
memset(dis, 0x3f, sizeof dis);
dis[s] = 0;
q.push((node){s, 0});
while (!q.empty()) {
node now = q.top();
q.pop();
int cur = now.y;
if (vis[cur]) continue;
vis[cur] = 1;
for (auto nxt : nbr[cur]) {
int to = nxt.to, w = nxt.dis;
if (dis[to] > dis[cur] + w) {
dis[to] = dis[cur] + w;
q.push((node){to, dis[to]});
}
}
}
}
int main() {
int s;
cin >> n >> m >> s;
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
nbr[u].emplace_back((Edge){v, w});
}
dijkstra(s);
for (int i = 1; i <= n; i++)
cout << dis[i] << " ";
return 0;
}
(
这份优化后的代码可以通过P4779。
小结
关于单源最短路径 Dijkstra 算法的介绍就到这里。Dijkstra 算法的时间复杂度其实相当优秀,是最短路算法的首选。在无权图中,优先选择 BFS,而在正权图中,优先选择 Dijkstra。而遇到负权图,我们又该怎么办呢?让我们一起期待下一次的最短路算法!
再见!
本文作者:Weekoder
本文链接:https://www.cnblogs.com/Weekoder/p/18240210
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步