题解:洛谷 P5143 攀爬者
【题目来源】
洛谷:P5143 攀爬者 - 洛谷(luogu.com.cn)
【题目描述】
HKE 考完 GDOI 之后跟他的神犇小伙伴们一起去爬山。
他在地形图上标记了 \(N\) 个点,每个点 \(P_i\) 都有一个坐标 \((x_i,y_i,z_i)\)。所有点对中,高度值 \(z\) 不会相等。HKE 准备从最低的点爬到最高的点,他的攀爬满足以下条件:
(1)经过他标记的每一个点;
(2)从第二个点开始,他经过的每一个点高度 \(z\) 都比上一个点高;
(3) HKE 会飞,他从一个点 \(P_i\) 爬到 \(P_j\) 的距离为两个点的欧几里得距离。即,

现在,HKE 希望你能求出他攀爬的总距离。
【输入】
第一行,一个整数 \(N\) 表示地图上的点数。
接下来 \(N\) 行,三个整数 \(x_i,y_i,z_i\) 表示第 \(i\) 个点的坐标。
【输出】
一个实数,表示 HKE 需要攀爬的总距离(保留三位小数)
【输入样例】
5
2 2 2
1 1 1
4 4 4
3 3 3
5 5 5
【输出样例】
6.928
【核心思想】
-
问题分析:给定 \(N\) 个三维空间中的点,每个点的高度 \(z\) 互不相同。需要从高度最低的点出发,依次经过所有点,且高度严格递增(即按 \(z\) 从小到大访问)。要求计算总欧几里得距离。由于访问顺序由高度唯一确定(按 \(z\) 升序),只需将点按 \(z\) 排序,然后依次计算相邻点的距离并累加。
-
算法选择:
- 结构体 + 排序:定义结构体存储 \(x, y, z\) 坐标。按 \(z\) 从小到大排序。然后遍历排序后的数组,累加相邻点之间的三维欧几里得距离。
- 复杂度:时间复杂度 \(O(N \log N)\),空间复杂度 \(O(N)\)。
-
关键步骤:
- 读入:读取 \(N\) 和每个点的坐标。
- 排序:按 \(z\) 升序排序。
- 距离累加:循环 \(i\) 从 1 到 \(N-1\),计算
sqrt((x_i-x_{i+1})^2 + (y_i-y_{i+1})^2 + (z_i-z_{i+1})^2)并累加。 - 输出:保留三位小数输出总距离。
-
时间/空间复杂度:
- 时间复杂度:\(O(N \log N)\)。
- 空间复杂度:\(O(N)\)。
-
排序与路径:
- 唯一路径:由于高度互不相同,按 \(z\) 排序后,访问顺序是唯一的,无需额外搜索。
- 欧几里得距离:使用三维距离公式计算。
- 适用场景:这类“按某一维度排序后求路径总长”的问题,是排序的简单应用。
【解题思路】

【算法标签】
普及- #其他排序
【代码详解】
#include <bits/stdc++.h> // 包含常用的头文件
using namespace std;
// 定义山峰结构体,包含三维坐标 (x, y, z)
struct mountain {
int x, y, z;
}m[50005]; // 定义一个最多可以存储50005座山峰的数组
// 自定义比较函数,用于排序
bool cmp(mountain x, mountain y)
{
// 按 z 坐标从小到大排序
return x.z < y.z;
}
int n; // n: 山峰的总数
double dis = 0; // dis: 总距离,用于存储所有相邻山峰之间的距离之和
int main()
{
// 输入山峰的总数 n
cin >> n;
// 输入每座山峰的三维坐标 (x, y, z)
for (int i=1; i<=n; i++) {
cin >> m[i].x >> m[i].y >> m[i].z;
}
// 对山峰数组按 z 坐标从小到大排序
sort(m+1, m+n+1, cmp);
// 计算相邻山峰之间的三维欧几里得距离,并累加到总距离 dis 中
for (int i=1; i<n; i++) {
dis += sqrt(
(m[i].x - m[i+1].x) * (m[i].x - m[i+1].x) + // x 坐标差的平方
(m[i].y - m[i+1].y) * (m[i].y - m[i+1].y) + // y 坐标差的平方
(m[i].z - m[i+1].z) * (m[i].z - m[i+1].z) // z 坐标差的平方
);
}
// 输出总距离,保留三位小数
printf("%.3f", dis);
return 0; // 程序结束
}
【运行结果】
5
2 2 2
1 1 1
4 4 4
3 3 3
5 5 5
6.928
浙公网安备 33010602011771号