最大化糖果美味指值问题 | 豆包MarsCode AI刷题

89 阅读3分钟

问题描述

小C面临一个选择问题:她可以从编号为1到n的糖果中任意选择一些糖果作为奖励,但需要遵守一个限制规则:如果选择了编号为i的糖果,那么编号为i-1、i-2、i+1、i+2的糖果将不能被选择。每个糖果都有一个对应的美味值,小C希望所选糖果的美味值之和最大。

例如:当有7个糖果,编号为1到7,美味值分别为 3, 1, 2, 7, 10, 2, 4,小C可以选择编号为1、4、7的糖果,这样可以得到最大美味值之和为 3 + 7 + 4 = 14

解题思路

  1. 动态规划

    此题可以用动态规划的方法解决。动态规划的核心思想是将问题分解为子问题,并通过存储子问题的解来避免重复计算。

  2. 状态定义

    在这个问题中,可以定义一个状态 dp[i],表示在前 i 个糖果中,选择第 i 个糖果时的最大美味值之和。

  3. 状态转移方程

    • 如果选择了第 i 个糖果,那么就不能选择第 i-1i-2i+1i+2 个糖果。
    • 因此,dp[i] 可以由 dp[i-3]dp[i-4]dp[i-5] 等状态转移而来。
    • 具体的状态转移方程为:dp[i] = max(dp[i-3], dp[i-4], dp[i-5], ...) + a[i]
  4. 初始化

    对于前几个糖果,需要手动初始化 dp 数组,因为它们没有足够的前置状态。

  5. 最终结果

    最终的最大美味值之和应该是 dp 数组中的最大值。

代码实现

以下是上述解题思路的Java实现代码

public class Main {
    public static int solution(int n, int[] a) {
        // write code here
        // 如果糖果数量小于等于2,直接返回最大值
        if (n <= 2) {
            return Math.max(a[0], a[1]);
        }

        // 定义dp数组,dp[i]表示选择第i个糖果时的最大美味值之和
        int[] dp = new int[n];

        // 初始化前几个糖果的dp值
        dp[0] = a[0];
        dp[1] = a[1];
        dp[2] = a[2];

        // 遍历每个糖果,计算dp值
        for (int i = 3; i < n; i++) {
            // 初始化dp[i]为a[i],因为至少要选择当前糖果
            dp[i] = a[i];

            // 从i-3到0遍历,找到最大值
            for (int j = i - 3; j >= 0; j--) {
                // 更新dp[i]
                dp[i] = Math.max(dp[i], dp[j] + a[i]);
            }
        }

        // 返回dp数组中的最大值
        int maxSum = 0;
        for (int i = 0; i < n; i++) {
            maxSum = Math.max(maxSum, dp[i]);
        }

        return maxSum;
    }

    public static void main(String[] args) {
        System.out.println(solution(7, new int[]{3, 1, 2, 7, 10, 2, 4}) == 14);
        System.out.println(solution(5, new int[]{1, 10, 2, 5, 8}) == 18);
        System.out.println(solution(6, new int[]{4, 5, 6, 1, 2, 3}) == 9);
    }
}

代码中的关键点

  1. 初始化:前几个糖果的 dp 值需要手动初始化。
  2. 状态转移:在遍历每个糖果时,从 i-3 到 0 遍历,找到最大值并更新 dp[i]
  3. 最终结果:返回 dp 数组中的最大值。

总结

在此题中,我们可以通过动态规划的方法逐步构建最优解。其中的运算关键在于定义好状态和状态转移方程,并正确初始化前几个糖果的状态。最终遍历 dp 数组,找到最大值即可。