动态规划解决「严格递增怪物序列」MarksCode6问题攻略

23 阅读3分钟

题目概述

小E需要在一个按顺序出现的怪物序列中选择击败怪物,要求满足:

  1. 每个被击败的怪物血量和攻击力都严格小于小E当前属性
  2. 被击败的怪物序列中,后一个怪物的血量和攻击力必须严格大于前一个

输入:怪物数量n,初始血量H,初始攻击A,怪物血量数组h,攻击数组a
输出:最多能击败的怪物数量

问题分析

关键约束点:

  1. 双条件筛选:怪物必须同时满足h[i]<当前H且a[i]<当前A才能被选择
  2. 严格递增序列:后选怪物的h和a必须都>前一个的h和a
  3. 顺序处理:怪物按出现顺序处理,但可以跳过任意个

解决思路

分步策略

  1. 预处理过滤:先筛选出所有可能击败的怪物(h<初始H且a<初始A)
  2. 转换为LIS问题:在有效怪物中寻找最长的严格递增子序列(按h和a同时递增)
  3. 动态规划求解:使用经典LIS解法处理双维度的递增条件

算法选择

  • 动态规划:时间复杂度O(n²),适用于n<100的数据规模

  • 状态定义:dp[i]表示以第i个怪物结尾的最长序列长度

  • 转移方程

    dp[i] = max(dp[j] + 1) ∀j < i且h[i]>h[j]a[i]>a[j]
    

代码实现

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MonsterHunter {
    public static int maxMonsters(int n, int H, int A, int[] h, int[] a) {
        // Step1: 预处理有效怪物
        List<int[]> valid = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (h[i] < H && a[i] < A) {
                valid.add(new int[]{h[i], a[i]});
            }
        }
        if (valid.isEmpty()) return 0;

        // Step2: 动态规划求解最长递增子序列
        int[] dp = new int[valid.size()];
        Arrays.fill(dp, 1);
        int max = 1;
        
        for (int i = 0; i < valid.size(); i++) {
            for (int j = 0; j < i; j++) {
                int[] cur = valid.get(i);
                int[] pre = valid.get(j);
                if (cur[0] > pre[0] && cur[1] > pre[1]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            max = Math.max(max, dp[i]);
        }
        return max;
    }
}

复杂度分析

  • 时间复杂度:O(n²)

    • 预处理阶段:O(n)
    • 动态规划阶段:双重循环O(m²),其中m为有效怪物数量(m ≤ n)
  • 空间复杂度:O(n)

    • 存储有效怪物列表:O(n)
    • DP数组:O(n)

关键点解析

  1. 预处理的重要性:直接过滤掉不可能击败的怪物,避免无效计算
  2. 双维度比较:必须同时比较血量和攻击力两个维度
  3. 严格递增要求:注意是严格大于(>),不是大于等于
  4. 初始属性不变:题目中击败怪物后小E的属性不会变化(易错点!)

测试样例验证

样例1

输入:

n=3, H=4, A=5
h=[1,2,3], a=[3,2,1]

处理流程:

  1. 有效怪物:[所有三个都满足h<4且a<5]

  2. 寻找严格递增序列:

    • [1,3] -> 无法找到后续更大的
    • [2,2] -> 无法找到后续更大的
    • [3,1] -> 无法找到后续更大的
      输出:1

样例3

输入:

n=4, H=20, A=25
h=[10,15,18,22], a=[12,18,20,26]

处理流程:

  1. 有效怪物:前三项(22的a=26 >25被过滤)
  2. 最长序列:10/12 →15/18 →18/20
    输出:3

总结

本题的解题关键在于将原问题转化为二维LIS问题。通过以下步骤保证正确性:

  1. 预处理过滤不可击败的怪物
  2. 在有效怪物序列中寻找最长的双严格递增子序列
  3. 使用标准LIS解法处理二维条件

扩展思考:如果小E击败怪物后属性会变化(如增加),问题将变得复杂得多,可能需要使用完全不同的贪心策略或状态压缩DP来解决。