题解:洛谷 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

【核心思想】

  1. 问题分析:给定 \(N\) 个三维空间中的点,每个点的高度 \(z\) 互不相同。需要从高度最低的点出发,依次经过所有点,且高度严格递增(即按 \(z\) 从小到大访问)。要求计算总欧几里得距离。由于访问顺序由高度唯一确定(按 \(z\) 升序),只需将点按 \(z\) 排序,然后依次计算相邻点的距离并累加。

  2. 算法选择

    • 结构体 + 排序:定义结构体存储 \(x, y, z\) 坐标。按 \(z\) 从小到大排序。然后遍历排序后的数组,累加相邻点之间的三维欧几里得距离。
    • 复杂度:时间复杂度 \(O(N \log N)\),空间复杂度 \(O(N)\)
  3. 关键步骤

    • 读入:读取 \(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) 并累加。
    • 输出:保留三位小数输出总距离。
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N)\)
    • 空间复杂度:\(O(N)\)
  5. 排序与路径

    • 唯一路径:由于高度互不相同,按 \(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
posted @ 2026-08-31 09:27  团爸讲算法  阅读(12)  评论(0)    收藏  举报