【贪心算法】洛谷P4995 - 跳跳

2025 - 01 - 21 - 第 44 篇
【洛谷】贪心算法题单 -【 贪心算法】 - 【学习笔记】
作者(Author): 郑龙浩 / 仟濹(CSND账号名)

目录

文章目录

  • 目录
  • 洛谷P4995 跳跳!
    • 题目描述
    • 输入格式
    • 输出格式
    • 样例 #1
      • 样例输入 #1
      • 样例输出 #1
    • 样例 #2
      • 样例输入 #2
      • 样例输出 #2
    • 提示
        • 样例解释
        • 数据范围
    • 思路
    • 代码

洛谷P4995 跳跳!

题目描述

你是一只小跳蛙,你特别擅长在各种地方跳来跳去。

这一天,你和朋友小 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 (hihj)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 1in,有 0 < h i ≤ 1 0 4 0 < h_i \leq 10 ^ 4 0<hi104,且保证 h i h_i hi 互不相同。

对于 10 % 10\% 10% 的数据, n ≤ 3 n \leq 3 n3

对于 20 % 20\% 20% 的数据, n ≤ 10 n \leq 10 n10

对于 50 % 50\% 50% 的数据, n ≤ 20 n \leq 20 n20

对于 80 % 80\% 80% 的数据, n ≤ 50 n \leq 50 n50

对于 100 % 100\% 100% 的数据, n ≤ 300 n \leq 300 n300

思路

  1. 先将石头进行 排序(从低到高 从高到低 都是可以)
  2. 然后从 「地面」跳到「最高的石头」,再从「最高的石头」跳到「距离地面最近的石头」,再跳到「第二高的石头」,再跳到「距离地面最近的第2个石头」,以此类推,每跳一次计算其使用的体力多少
  3. 计算公式为:(「第 i 块石头的高度」-「第 j 块石头的高度」)^ 2 / 「第 i 块石头的高度」^ 2

代码

// 洛谷 p4995 跳跳
// 思路:
// 1. 先将石头进行 排序(从低到高 从高到低 都是可以)
// 2. 然后从 「地面」跳到「最高的石头」,再从「最高的石头」跳到「距离地面最近的石头」,再跳到「第二高的石头」,再跳到「距离地面最近的第2个石头」,以此类推,每跳一次计算其使用的体力多少
// 3. 计算公式为:(「第i块石头的高度」-「第j块石头的高度」)^2  / 「第i块石头的高度」^2
#include 
#include 
using namespace std;
int main( void ){
    int num; // 石头数量
    cin >> num;
    // 一定要记住: 用 了long long 不要用 int,否则数大了会存不开,导致测试点错一半
    long long data[ 500 ] = { 0 }; // 每个石头的高度 //记得初始化为0,因为data[0]必须为0,这个代表的是地面的高度
    for( int i = 1; i < num + 1; i ++ ){
        cin >> data[ i ];
    }
    sort( data + 1, data + num + 1); // 升序排序
    long long  sum = 0; // 总体力值 --> 一定要记住: 用 了long long 不要用 int,否则数大了会存不开,导致测试点错一半
    // 两个坐标是从第一块石头到最后一块石头的前一块(最后一块石头已经算出来了)
    int i = 0; // 地面 / 低的石头
    int j = num; // 高的石头

    while( 1 ){
        // 循环条件: 定位坐标(浮标)分别在左右两侧,直到 左侧浮标与右侧浮标 重合

        // 一个循环: 从下往上蹦 一次,从上往下蹦一次 ,一次循环,蹦哒两次
        if( i == j ) break;
        sum += (data[ j ] - data[ i ]) * (data[ j ] - data[ i ]); // i 跳到 j (从下往上跳)两个石头之间蹦哒 所花费的体力是多少
        i ++; // 下面的浮标向上一个
        if( i == j ) break;
        sum += (data[ j ] - data[ i ]) * (data[ j ] - data[ i ]); // j 跳到 i (从上往下跳)
        j --; // 上面的浮标向下一个
    }
    cout << sum;
    return 0;
}

你可能感兴趣的:(算法学习笔记,贪心算法,算法)