动态规划解决HJ103梅花桩跳跃问题

Redraiment 是走梅花桩的高手。现在,地上有 n个梅花桩排成一排,从前到后高度依次为 h1,h2,…,hn

Redraiment 可以任选一个梅花桩开始,向后跳到任意一个比当前高度高的梅花桩上。

求 Redraiment 最多可以跳过多少个梅花桩。

输入描述: 第一行输入一个整数 n(1≦n≦200) 代表梅花桩的数量。 第二行入n个整数, h1,h2,…,hn(1≦hi≦350)代表每一个梅花桩的高度。

输出描述: 输出一个正整数,代表 Redraiment 最多可以跳过多少个梅花桩。 

输入:

6
2 5 1 5 4 5

输出:

3

说明:

在这个样例中,其中一个最优的选择是,从第一个桩子起跳,最多可以跳三个梅花桩,使用橙色加粗标识:{2,5,1,5,4,5}。
另外一种最优选择是,从第三个桩子起跳,最多也可以跳三个梅花桩,使用橙色加粗标识:{2,5,1,5,4,5}。

解法一:记负均正法

import java.util.*;
public class Main{

    public static void main(String[] arg) {
        Scanner scan = new Scanner(System.in);
        while (scan.hasNext()) {
            scan.nextLine();
            String[] input1 = scan.nextLine().split(" ");
            int[] intArr = Arrays.stream(input1).mapToInt(Integer::parseInt).toArray();
            int[] k=new int[intArr.length];
            for(int j=1;j<intArr.length;j++){
                for(int i=0;i<j;i++){
                    if(intArr[i]<intArr[j]){
                        k[j]=Math.max(k[j],k[i]+1);
                    }
                }
            }
            Arrays.sort(k);
            System.out.println(k[k.length-1]+1);
        }
    }
}

解法二:动态规划法

动态规划思路:
  1. 定义状态

    • dp[i] 表示以第 i 个梅花桩结尾的最长递增子序列的长度。

  2. 初始化

    • 每个 dp[i] 初始化为 1,因为至少可以单独选择自己。

  3. 状态转移

    • 对于每个 i,遍历所有 j < i

      • 如果 h[j] < h[i],则 dp[i] = max(dp[i], dp[j] + 1)

      • 这表示如果可以从 j 跳到 i,则更新 dp[i]

  4. 结果

    • dp 数组中的最大值就是答案。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int[] heights = new int[n];
        for (int i = 0; i < n; i++) {
            heights[i] = scanner.nextInt();
        }

        int[] dp = new int[n];
        Arrays.fill(dp, 1); // 初始化为 1

        int maxLen = 1; // 至少可以跳 1 个梅花桩
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (heights[j] < heights[i]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            maxLen = Math.max(maxLen, dp[i]);
        }

        System.out.println(maxLen);
    }
}

为什么更新 dp[i] 而不是 dp[j]

动态规划的核心是状态定义状态转移。在这里:

  • 状态定义dp[i] 表示以第 i 个梅花桩结尾的最长递增子序列的长度。

  • 状态转移:对于每个 i,我们需要找到所有 j < i 且 heights[j] < heights[i] 的 j,然后用 dp[j] + 1 来更新 dp[i]

 

示例:

输入:

6
2 5 1 5 4 5

DP 数组填充过程:

  • dp = [1, 1, 1, 1, 1, 1](初始化)

  • i=1(高度 5):

    • j=0(高度 2):2 < 5 → dp[1] = max(1, dp[0]+1=2) → dp = [1, 2, 1, 1, 1, 1]

  • i=2(高度 1):

    • j=0(高度 2):2 > 1 → 跳过

    • j=1(高度 5):5 > 1 → 跳过

    • dp[2] 保持 1 → dp = [1, 2, 1, 1, 1, 1]

  • i=3(高度 5):

    • j=0(高度 2):2 < 5 → dp[3] = max(1, dp[0]+1=2) → dp = [1, 2, 1, 2, 1, 1]

    • j=1(高度 5):5 == 5 → 跳过

    • j=2(高度 1):1 < 5 → dp[3] = max(2, dp[2]+1=2) → 保持 2

  • i=4(高度 4):

    • j=0(高度 2):2 < 4 → dp[4] = max(1, dp[0]+1=2) → dp = [1, 2, 1, 2, 2, 1]

    • j=1(高度 5):5 > 4 → 跳过

    • j=2(高度 1):1 < 4 → dp[4] = max(2, dp[2]+1=2) → 保持 2

    • j=3(高度 5):5 > 4 → 跳过

  • i=5(高度 5):

    • j=0(高度 2):2 < 5 → dp[5] = max(1, dp[0]+1=2) → dp = [1, 2, 1, 2, 2, 2]

    • j=1(高度 5):5 == 5 → 跳过

    • j=2(高度 1):1 < 5 → dp[5] = max(2, dp[2]+1=2) → 保持 2

    • j=3(高度 5):5 == 5 → 跳过

    • j=4(高度 4):4 < 5 → dp[5] = max(2, dp[4]+1=3) → dp = [1, 2, 1, 2, 2, 3]

  • maxLen 为 dp 数组的最大值 3。

输出:3

复杂度分析:
  • 时间复杂度:O(n²),因为有两层嵌套循环。

  • 空间复杂度:O(n),用于存储 dp 数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值