题解:P3371 【模板】单源最短路径(弱化版)

题目都说了可以用 SPFA 啊,秀啥 Dijkstra 啊!

先介绍一下 SPFA 死了的算法。

SPFA 算法,全名 Shortest Path Faster Algorithm,是一种用于解决单源最短路径问题的算法,它是 Bellman-Ford 算法的改进版本。SPFA 算法可以处理带有负权边的图,但不能处理带有负权环的图。算法的基本思想是使用一个队列来存储所有待优化的节点,并通过不断的松弛操作来逼近最短路径。

注:来源于网络。

SPFA 的基本步骤

  1. 初始化答案数组,全部设为无穷大。

  2. 将源点加入队列,打上在队列的标记,将到起点的答案设为 00。

  3. 队列非空时,取出队首元素存下后立即取消标记并弹出队首元素,并对其所有出边进行松弛操作。

  4. 如果松弛成功,并且终点不在队列中,则将终点加入队列并打上在队列的标记。

  5. 重复步骤 33 和 44,直到队列为空。

手玩一下样例

样例如图

将答案数组记作 dis,是否在队列的标记数组记作 vis。

最开始的 dis 与 vis 如下图。

最开始的队列如下图。

第一轮,取队首元素 11,此时 11 能松弛 22、33、44,且 22、33、44 都不在队列中,都没打标记,所以将这几个数全部扔进队列并打上标记。

此时的 dis、vis、队列如下图。

第二轮,取队首元素 22,此时 22 能松弛 33 和 44,但 33 和 44 都在队列中,都打了标记,所以不再扔进队列。

此时的 dis、vis、队列如下图。

第三轮,取队首元素 33,此时 33 不能松弛任何一个点。

此时的 dis、vis、队列如下图。

第三轮,取队首元素 44,此时 44 不能松弛任何一个点。

此时的 dis、vis、队列如下图。

此时队列已经空了,结束。

放代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# include <bits/stdc++.h>
using namespace std;
int n , m , s , u , v , w , dis[10010];
bool vis[10010];
vector <pair <int , int> > g[10010];
void bfs()
{
for(int i = 1 ; i <= n ; i ++)
{
dis[i] = 1e9;
}
queue <int> q;
q.push(s);
vis[s] = 1;
dis[s] = 0;
while(!q.empty())
{
int t = q.front();
q.pop();
vis[t] = 0;
for(int i = 0 ; i < g[t].size() ; i ++)
{
if(dis[g[t][i].first] > dis[t] + g[t][i].second)
{
dis[g[t][i].first] = dis[t] + g[t][i].second;
if(vis[g[t][i].first])
{
continue;
}
vis[g[t][i].first] = 1;
q.push(g[t][i].first);
}
}
}
return ;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m >> s;
for(int i = 1 ; i <= m ; i ++)
{
cin >> u >> v >> w;
g[u].push_back({v , w});
}
bfs();
for(int i = 1 ; i <= n ; i ++)
{
if(dis[i] == 1e9)
{
cout << (1LL << 31) - 1 << " ";
}
else
{
cout << dis[i] << " ";
}
}
return 0;
}

题解:P3371 【模板】单源最短路径(弱化版)
http://zhangyimin12345.github.io/posts/cmamfvq67001ah8363u08et1n/
作者
zhangyimin12345
发布于
2025年5月9日
更新于
2025年5月9日
许可协议