csp信奥赛C++高频考点专项训练之贪心算法 --【跳跃与过河问题】:跳跳!

题目描述
你是一只小跳蛙,你特别擅长在各种地方跳来跳去。
这一天,你和朋友小 F 一起出去玩耍的时候,遇到了一堆高矮不同的石头,其中第 i i i 块的石头高度为 h i h_i hi,地面的高度是 h 0 = 0 h_0 = 0 h0=0。你估计着,从第 i i i 块石头跳到第 j j j 块石头上耗费的体力值为 ( h i − h j ) 2 (h_i - h_j) ^ 2 (hi−hj)2,从地面跳到第 i i i 块石头耗费的体力值是 ( h i ) 2 (h_i) ^ 2 (hi)2。
为了给小 F 展现你超级跳的本领,你决定跳到每个石头上各一次,并最终停在任意一块石头上,并且小跳蛙想耗费尽可能多的体力值。
当然,你只是一只小跳蛙,你只会跳,不知道怎么跳才能让本领更充分地展现。
不过你有救啦!小 F 给你递来了一个写着 AK 的电脑,你可以使用计算机程序帮你解决这个问题,万能的计算机会告诉你怎么跳。
那就请你------会写代码的小跳蛙------写下这个程序,为你 NOIp AK 踏出坚实的一步吧!
输入格式
输入一行一个正整数 n n n,表示石头个数。
输入第二行 n n n 个正整数,表示第 i i i 块石头的高度 h i h_i hi。
输出格式
输出一行一个正整数,表示你可以耗费的体力值的最大值。
输入输出样例 1
输入 1
2
2 1
输出 1
5
输入输出样例 2
输入 2
3
6 3 5
输出 2
49
说明/提示
样例解释
两个样例按照输入给定的顺序依次跳上去就可以得到最优方案之一。
数据范围
对于 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n,有 0 < h i ≤ 10 4 0 < h_i \leq 10 ^ 4 0<hi≤104,且保证 h i h_i hi 互不相同。
对于 10 % 10\% 10% 的数据, n ≤ 3 n \leq 3 n≤3;
对于 20 % 20\% 20% 的数据, n ≤ 10 n \leq 10 n≤10;
对于 50 % 50\% 50% 的数据, n ≤ 20 n \leq 20 n≤20;
对于 80 % 80\% 80% 的数据, n ≤ 50 n \leq 50 n≤50;
对于 100 % 100\% 100% 的数据, n ≤ 300 n \leq 300 n≤300。
思路分析
这是一道贪心 + 排序的题目。为了消耗最多的体力值,每次跳跃都应选择与当前石头高度差最大的未访问石头。由于体力值与高度差的平方成正比,平方函数是凸函数,因此极端值(最高、最低)之间的差会产生最大的平方值。
贪心策略:
- 将所有石头按高度升序排序。
- 从地面出发,先跳到最高的石头(因为地面高度为0,跳最高得到最大平方)。
- 然后跳到当前最低的石头,再跳到当前最高的石头,依此类推,形成"之"字形路径。
- 使用两个指针
l和r分别指向未访问的最低和最高石头,交替访问,直到所有石头都被跳过。
这样每一步都保证了当前石头与上一次石头的差值尽可能大,从而总体力值最大。
代码实现
cpp
#include <bits/stdc++.h>
using namespace std;
long long n , a[310];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
sort(a + 1, a + n + 1); //升序排序,范围[1, n]
long long ans = 0; //体力值可能很大,用long long
int l = 1, r = n; //左右指针,指向未跳的石头
int cur = 0; //当前所在高度,初始为地面0
bool flag = true; //true表示下次取最大,false表示取最小
while (l <= r) {
if (flag) { //取当前最大高度的石头
ans += (a[r] - cur) * (a[r] - cur);
cur = a[r];
r--;
} else { //取当前最小高度的石头
ans += (a[l] - cur) * (a[l] - cur);
cur = a[l];
l++;
}
flag = !flag; //交替方向
}
cout << ans << endl;
return 0;
}
功能分析
- 输入:第一行整数 n(石头个数,n ≤ 300),第二行 n 个互不相同的正整数(高度 ≤ 10000)。
- 处理 :
- 将石头高度存入数组 a[1...n] 并升序排序。
- 初始化当前高度 cur = 0(地面),左右指针 l=1(最小),r=n(最大)。
- 交替选择当前最大和最小石头跳跃:
- 从当前高度跳到最大石头(若 flag==true)
- 从当前高度跳到最小石头(若 flag==false)
- 每次跳跃后更新 cur 为落脚点高度,并移动对应指针。
- 循环直到所有石头都被跳过(l > r)。
- 输出:最大可能消耗的体力值(整数)。
- 正确性:贪心策略保证每次跳跃选择极端高度差,平方函数凸性使得总和最大。
- 复杂度:O(n log n) 时间,O(1) 额外空间(不计输入数组)。
各种学习资料,助力大家一站式学习和提升!!!
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"########## 一站式掌握信奥赛知识! ##########";
cout<<"############# 冲刺信奥赛拿奖! #############";
cout<<"###### 课程购买后永久学习,不受限制! ######";
return 0;
}
【秘籍汇总】(完整csp信奥赛C++学习资料):
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转
4、csp信奥赛冲刺一等奖有效刷题题解:
CSP信奥赛C++初赛及复赛高频考点真题解析(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}