问题描述
小R在接下来的n天里想要尽可能多地吃糖果。为了保持健康和节省零花钱,她规定如果今天吃了糖果,明天就不能吃。不过,小R允许自己有k次机会打破这个规则,在连续两天都吃糖果。她希望通过合理安排每天是否吃糖果,获得最大的糖果美味值。你的任务是帮助小R规划她的吃糖果方案,以使她吃到的糖果美味值最大。
输入
n:天数k:允许打破规则的次数a:一个长度为n的数组,表示每天糖果的美味值
输出
一个整数,表示小R能获得的最大美味值
解题思路
1. 动态规划
我们可以使用动态规划来解决这个问题。定义一个二维数组 dp,其中 dp[i][j] 表示在前 i 天中,使用 j 次打破规则的机会所能获得的最大美味值。
2. 状态转移
- 今天不吃糖果:
dp[i][j] = dp[i - 1][j] - 今天吃糖果,昨天不吃:
dp[i][j] = max(dp[i][j], dp[i - 2][j] + a[i - 1]) - 今天吃糖果,昨天也吃(使用一次机会) :
dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + a[i - 1])
3. 初始化
- 当
i = 1时,dp[1][j] = a[0],因为第一天无论如何都可以吃糖果。
4. 最终结果
- 最终结果为
dp[n][k],即在前n天中,使用k次打破规则的机会所能获得的最大美味值。
数据结构
二维数组 dp:dp[i][j] 表示在前 i 天中,使用 j 次打破规则的机会所能获得的最大美味值。
算法步骤
- 初始化
dp数组。 - 遍历每一天和每次打破规则的机会。
- 根据状态转移方程更新
dp数组。 - 返回
dp[n][k]作为最终结果。
算法复杂度
- 时间复杂度:
O(n * k),其中n是天数,k是允许打破规则的次数。 - 空间复杂度:
O(n * k),用于存储dp数组。
代码实现
int solution(int n, int k, vector<int> a) {
// dp[i][j] 表示在前 i 天中,使用 j 次打破规则的机会所能获得的最大美味值
vector<vector<int>> dp(n + 1, vector<int>(k + 1, 0));
// 初始化边界条件
for (int i = 1; i <= n; ++i) {
for (int j = 0; j <= k; ++j) {
// 今天不吃糖果
dp[i][j] = dp[i - 1][j];
// 今天吃糖果,昨天不吃
if (i > 1) {
dp[i][j] = max(dp[i][j], dp[i - 2][j] + a[i - 1]);
} else {
dp[i][j] = max(dp[i][j], a[i - 1]);
}
// 今天吃糖果,昨天也吃(使用一次机会)
if (j > 0) {
dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + a[i - 1]);
}
}
}
// 返回最大美味值
return dp[n][k];