1 条题解
-
0
第三部分:题目分析与标准代码
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
- 上传者