「学习笔记」Dijkstra
$Dijkstra$ 是高效的处理最短路的算法,但是它不可以处理有负权的图。
算法大致流程:
-
初始化最短路数组 $dis$ 全部为 $inf$,起点 $s$ 设为 $0$。
-
松弛 $s$ 指向的点。
-
在这些点里找到 $dis$ 值最小的一个,并松弛这个点指向的边。
-
重复上一步操作,直到找点时最小的那一个是 $0$,结束算法。
Code
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 5e5 + 50, inf = 2147483647;
int n, m, s, cnt, dis[maxn];
int head[maxn];
bool vis[maxn];
struct edge
{
int to, w, nxt;
} e[maxn];
void add(int u, int v, int w)
{
e[++ cnt].to = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt;
}
void Dijkstra()
{
for (int i = 1; i <= n; i++)
dis[i] = inf;
dis[s] = 0, dis[0] = inf;
while (true)
{
int u = 0;
for (int i = 1; i <= n; i++)
if (!vis[i] && dis[u] > dis[i]) u = i;
if (u == 0) break;
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to, w = e[i].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
}
}
}
}
int main()
{
cin >> n >> m >> s;
for (int i = 1, u, v, w; i <= m; i++)
{
cin >> u >> v >> w;
add(u, v, w);
}
Dijkstra();
for (int i = 1; i <= n; i++)
cout << dis[i] << ' ';
return 0;
}
计算得知,这个 $Dijkstra$ 程序的时间复杂度为 $O(n^2 + m)$,还可以优化。
使用小根堆的方法来优化。用这个小根堆来维护 $dis$ 最小的节点,用结构体记录编号和 $dis$,并用重载运算符来已 $dis_i$ 为关键字来进行排序,每次松弛成功就打包入堆。优化后的时间复杂度为 $O(m log m)$。
Code
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 5e5 + 50, inf = 2147483647;
int n, m, s, cnt, dis[maxn];
int head[maxn];
bool vis[maxn];
struct edge
{
int to, w, nxt;
} e[maxn];
void add(int u, int v, int w)
{
e[++ cnt].to = v;
e[cnt].w = w;
e[cnt].nxt = head[u];
head[u] = cnt;
}
struct node
{
int v, w;
friend bool operator < (node a, node b)
{
return a.w > b.w;
}
} tmp;
priority_queue <node> q;
void Dijkstra()
{
for (int i = 1; i <= n; i++)
dis[i] = inf;
dis[s] = 0;
tmp.v = s, tmp.w = 0;
q.push(tmp);
while (q.size())
{
int u = q.top().v;
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to, w = e[i].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
tmp.w = dis[v], tmp.v = e[i].to;
q.push(tmp);
}
}
}
}
int main()
{
cin >> n >> m >> s;
for (int i = 1, u, v, w; i <= m; i++)
{
cin >> u >> v >> w;
add(u, v, w);
}
Dijkstra();
for (int i = 1; i <= n; i++)
cout << dis[i] << ' ';
return 0;
}

浙公网安备 33010602011771号