题解:洛谷 P1339 Heat Wave
【题目来源】
洛谷:P1339 [USACO09OCT] Heat Wave G - 洛谷
【题目描述】
有一个 \(n\) 个点 \(m\) 条边的无向图,请求出从 \(s\) 到 \(t\) 的最短路长度。
【输入】
第一行四个正整数 \(n,m,s,t\)。
接下来 \(m\) 行,每行三个正整数 \(u,v,w\),表示一条连接 \(u,v\),长为 \(w\) 的边。
【输出】
输出一行一个整数,表示答案。
【输入样例】
7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1
【输出样例】
7
【核心思想】
-
问题分析:给定 \(n\) 个点、\(m\) 条边的无向带权图,求从 \(s\) 到 \(t\) 的最短路径长度。这是一个单源最短路问题,边权为正整数,适合使用 Dijkstra 算法。
-
算法选择:
- Dijkstra(朴素版):适用于稠密图(邻接矩阵存储),每次 \(O(n)\) 找最小距离点,总复杂度 \(O(n^2)\)
- 反向求解技巧:代码中调用
dij(t)从终点 \(t\) 出发,输出 \(d[s]\),等价于从 \(s\) 到 \(t\) 的最短路(无向图对称性)
-
关键步骤:
- 初始化:邻接矩阵 \(e\) 初始化为 \(\infty\)(
0x3f),读入 \(n, m, s, t\) 和 \(m\) 条无向边 - Dijkstra 过程(从源点 \(s\) 出发):
- 初始化距离数组 \(d[i] = \infty\),\(d[s] = 0\)
- 循环 \(n-1\) 次:
- 找未访问且距离最小的点 \(u\):\(u = \arg\min_{j \notin vis} d[j]\)
- 标记 \(vis[u] = 1\)
- 松弛所有点:\(d[j] = \min(d[j],\ d[u] + e[u][j])\)
- 输出:\(d[t]\)(代码中为 \(d[s]\),因从 \(t\) 反向计算)
- 初始化:邻接矩阵 \(e\) 初始化为 \(\infty\)(
-
时间/空间复杂度:
- 时间复杂度:\(O(n^2)\),每次找最小点 \(O(n)\),松弛 \(O(n)\),共 \(n-1\) 轮
- 空间复杂度:\(O(n^2)\),邻接矩阵存储
-
Dijkstra 的核心思想:
- 贪心选择:每次选择当前距离源点最近的未确定点,其最短距离已确定(正权边保证)
- 松弛操作:利用已确定最短距离的点更新其邻接点的距离上界
- 无向图对称性:\(d(s, t) = d(t, s)\),可从任一端点运行 Dijkstra
- 稠密图适配:邻接矩阵 + 朴素 \(O(n^2)\) 实现,在 \(n \le 2500\) 时比堆优化更简洁
- 适用于"正权无向图单源最短路"类问题,核心是贪心确定最短距离 + 松弛更新
【解题思路】

【算法标签】
普及 #Dijkstra
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int d[2505], vis[2505], e[5005][5005];
int n, m;
void dij(int s)
{
for (int i=0; i<=n; i++) { // 将n个点到s的距离都设置为最大值
d[i] = 1e9;
}
d[s] = 0; // 将源点到自己的距离设置为0
for (int i=1; i<n; i++) { // 枚举n-1个顶点
int u = 0; // 设计u节点,用来记录要出圈的节点
for (int j=1; j<=n; j++) { // 枚举n个顶点
if (!vis[j] && d[j]<d[u]) { // 如果这个点没有标记过,找到到源点最小距离的点
u = j; // 使用查找并交换的方式找
}
}
vis[u] = 1; // 标记到源点最小距离的点已出圈
for (int j=1; j<=n; j++) { // 遍历n个顶点
d[j] = min(d[j], d[u]+e[u][j]); // 求每个点到源点之前计算的距离,和出圈的点到源点的距离加上邻边的权重的最小值(如果某个点与u没有邻接关系,即为无穷大,这样保留之前到源点的距离)
}
}
}
int main()
{
int s, t;
memset(e, 0x3f, sizeof(e));
cin >> n >> m >> s >> t;
for (int i=0; i<m; i++) {
int u, v, w;
cin >> u >> v >> w;
e[u][v] = w;
e[v][u] = w;
}
dij(t);
cout << d[s] << endl;
return 0;
}
【运行结果】
7 11 5 4
2 4 2
1 4 3
7 2 2
3 4 3
5 7 5
7 3 3
6 1 1
6 3 4
2 4 3
5 6 3
7 2 1
7
浙公网安备 33010602011771号