题目解析
小C来到一家饭馆,这里有 ( n ) 道菜,每道菜有对应的价格和是否含有蘑菇的标记。小C想点 ( k ) 道菜,其中最多允许有 ( m ) 道菜含有蘑菇。她希望在满足上述条件的情况下,总价格尽可能低。如果无法满足条件,则输出 (-1)。
解题思路
这是一道经典的动态规划(DP)问题,目标是在一个限制条件下求最优解。可以通过三维状态数组来求解。以下是解题步骤:
1. 状态定义
定义一个三维 DP 数组 dp[i][j][l],表示:
- 考虑前 ( i ) 道菜。
- 已经选择了 ( j ) 道菜。
- 其中 ( l ) 道菜含有蘑菇。
- 此时的最小总价格。
2. 状态转移
-
不选第 ( i ) 道菜:
表示直接继承前 道菜的结果。
-
选第 ( i ) 道菜:
-
如果第 ( i ) 道菜含有蘑菇(( s[i-1] = '1' ) 且 ( l > 0 )):
[ -
如果第 ( i ) 道菜不含蘑菇(( s[i-1] = '0' )):
-
3. 边界条件
- 初始化
dp数组,所有状态设为不可达(math.MaxInt32),除了dp[0][0][0] = 0,表示未选择任何菜时总花费为 0。
4. 结果提取
- 遍历所有可能的蘑菇数量 ( l ),找到满足 ( dp[n][k][l] ) 的最小值。
- 如果最小值仍然是初始值,说明无法满足条件,返回 (-1)。
实现代码
package main
import (
"fmt"
"math"
)
func solution(s string, a []int, m int, k int) int64 {
n := len(a)
// 初始化 dp 数组
dp := make([][][]int, n+1)
for i := range dp {
dp[i] = make([][]int, k+1)
for j := range dp[i] {
dp[i][j] = make([]int, m+1)
for l := range dp[i][j] {
dp[i][j][l] = math.MaxInt32 // 初始化为不可达
}
}
}
// 初始状态
dp[0][0][0] = 0
// 动态规划
for i := 1; i <= n; i++ {
for j := 0; j <= k; j++ {
for l := 0; l <= m; l++ {
// 不选择第 i 道菜
dp[i][j][l] = dp[i-1][j][l]
// 选择第 i 道菜
if j > 0 {
if s[i-1] == '1' && l > 0 { // 第 i 道菜含有蘑菇
dp[i][j][l] = min(dp[i][j][l], dp[i-1][j-1][l-1]+a[i-1])
} else if s[i-1] == '0' { // 第 i 道菜不含蘑菇
dp[i][j][l] = min(dp[i][j][l], dp[i-1][j-1][l]+a[i-1])
}
}
}
}
}
// 提取结果
res := math.MaxInt32
for i := 0; i <= m; i++ {
res = min(res, dp[n][k][i])
}
if res == math.MaxInt32 {
res = -1
}
return int64(res)
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
func main() {
fmt.Println(solution("001", []int{10, 20, 30}, 1, 2) == 30)
fmt.Println(solution("111", []int{10, 20, 30}, 1, 2) == -1)
fmt.Println(solution("0101", []int{5, 15, 10, 20}, 2, 3) == 30)
}
复杂度分析
- 时间复杂度:
• 三重循环:外层循环遍历 ( n ) 道菜,第二层和第三层分别遍历 ( k ) 和 ( m ) 的限制。
• 总时间复杂度为 。
- 空间复杂度:
• 使用了三维数组 ( dp ),空间复杂度为 。