「学习笔记」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;
}
posted @ 2025-07-25 14:13  Aelt  阅读(19)  评论(0)    收藏  举报