1 条题解

  • 0
    @ 2025-12-9 17:10:46

    第三部分:题目分析与标准代码

    1. 解题思路

    • 模拟法:这是一个典型的模拟过程。我们需要遍历 NN 个点,计算相邻两个点(iii+1i+1)之间的代价并累加。
    • 距离计算:使用 <cmath> 库中的 abs() 函数计算绝对值。
    • 逻辑分支
      • 计算基础距离消耗:dist = abs(x2-x1) + abs(y2-y1)
      • 判断是否上坡:如果 h2 > h1,则 cost += (h2 - h1) * K
    • 数据类型:虽然单段消耗在 int 范围内,但累加总和建议使用 long long 以防溢出(尽管本题数据较小,养成好习惯很重要)。

    2. 标准代码 (C++14)

    /**
     * 题目:登山拉练 (Hiking Training)
     * 难度:GESP 4级
     * 知识点:模拟、结构体/数组、绝对值
     */
    
    #include <iostream>
    #include <cmath>    // 用于 abs() 函数
    #include <vector>
    
    using namespace std;
    
    // 为了代码清晰,定义一个结构体来存储点的属性
    struct Point {
        int x, y, h;
    };
    
    int main() {
        // 提升 cin/cout 速度
        ios::sync_with_stdio(false);
        cin.tie(NULL);
    
        int N, K;
        if (!(cin >> N >> K)) return 0;
    
        // 使用 vector 存储点的信息,下标从 1 开始方便逻辑对应
        vector<Point> p(N + 1);
    
        for (int i = 1; i <= N; ++i) {
            cin >> p[i].x >> p[i].y >> p[i].h;
        }
    
        long long total_cost = 0;
    
        // 循环遍历每一段路程:从第 i 点走到第 i+1 点
        // 注意循环范围是 1 到 N-1
        for (int i = 1; i < N; ++i) {
            // 1. 计算水平移动消耗 (曼哈顿距离)
            int dist = abs(p[i+1].x - p[i].x) + abs(p[i+1].y - p[i].y);
            total_cost += dist;
    
            // 2. 判断是否爬坡并计算额外消耗
            if (p[i+1].h > p[i].h) {
                int height_diff = p[i+1].h - p[i].h; // 相对高度
                total_cost += (long long)height_diff * K;
            }
        }
    
        cout << total_cost << endl;
    
        return 0;
    }
    

    第四部分:数据生成器

    这是一个用于生成 1.in ~ 10.in 及其对应标准答案的生成器代码。

    /**
     * GESP 4级 [登山拉练] - 数据生成器
     */
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <cmath>
    #include <cstdlib>
    #include <ctime>
    
    using namespace std;
    
    // 定义点结构体
    struct Point {
        int x, y, h;
    };
    
    // ------------------------------------------
    // 标准解法函数 (生成 .out)
    // ------------------------------------------
    long long solve(int N, int K, const vector<Point>& p) {
        long long ans = 0;
        // p 的下标从 0 开始,所以循环 0 到 N-2
        for (int i = 0; i < N - 1; ++i) {
            ans += abs(p[i+1].x - p[i].x) + abs(p[i+1].y - p[i].y);
            if (p[i+1].h > p[i].h) {
                ans += (long long)(p[i+1].h - p[i].h) * K;
            }
        }
        return ans;
    }
    
    // 辅助函数:生成范围内的随机数
    int randRange(int min, int max) {
        return rand() % (max - min + 1) + min;
    }
    
    int main() {
        srand(time(0));
        
        cout << "Start generating data..." << endl;
    
        for (int i = 1; i <= 10; ++i) {
            string in_name = to_string(i) + ".in";
            string out_name = to_string(i) + ".out";
            ofstream fin(in_name);
            ofstream fout(out_name);
    
            int N, K;
            vector<Point> points;
    
            // 构造不同类型的测试点
            if (i == 1) { 
                // 样例 1
                N=3; K=10; 
                points={{0,0,100}, {3,4,100}, {5,5,120}}; 
            }
            else if (i == 2) { 
                // 样例 2
                N=4; K=5; 
                points={{10,10,500}, {10,20,400}, {20,20,450}, {20,10,300}}; 
            }
            else if (i == 3) { 
                // 全平地 (h相同),只测曼哈顿距离
                N = 100; K = 20;
                for(int j=0; j<N; j++) points.push_back({j*10, j*10, 500});
            }
            else if (i == 4) { 
                // 全上坡 (持续累加 K)
                N = 50; K = 10;
                for(int j=0; j<N; j++) points.push_back({j, j, 100 + j*10});
            }
            else if (i == 5) { 
                // 全下坡 (不累加 K)
                N = 50; K = 10;
                for(int j=0; j<N; j++) points.push_back({j, j, 1000 - j*10});
            }
            else if (i == 6) { 
                // 原地爬楼 (x,y 不变,只变 h)
                N = 10; K = 100;
                for(int j=0; j<N; j++) points.push_back({50, 50, randRange(0, 1000)});
            }
            else if (i == 7) { 
                // 小规模随机
                N = 20; K = randRange(1, 50);
                for(int j=0; j<N; j++) points.push_back({randRange(0,100), randRange(0,100), randRange(0,500)});
            }
            else if (i == 8) { 
                // 大规模随机 (N=1000)
                N = 1000; K = randRange(1, 100);
                for(int j=0; j<N; j++) points.push_back({randRange(0,10000), randRange(0,10000), randRange(0,10000)});
            }
            else if (i == 9) { 
                // 剧烈起伏 (锯齿状地形:低-高-低-高)
                N = 100; K = 50;
                for(int j=0; j<N; j++) {
                    int h = (j % 2 == 0) ? 100 : 900;
                    points.push_back({j*10, 0, h});
                }
            }
            else { 
                // 极限数据
                N = 1000; K = 100;
                for(int j=0; j<N; j++) points.push_back({randRange(0,10000), randRange(0,10000), randRange(0,10000)});
            }
    
            // 写入输入文件
            fin << N << " " << K << endl;
            for(auto p : points) {
                fin << p.x << " " << p.y << " " << p.h << endl;
            }
    
            // 写入输出文件
            fout << solve(N, K, points) << endl;
    
            fin.close();
            fout.close();
            cout << "Generated Case " << i << endl;
        }
        
        cout << "Done!" << endl;
        return 0;
    }
    
    • 1

    信息

    ID
    19275
    时间
    1000ms
    内存
    32MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者