题目
题目链接
解题思路
使用动态规划求解:
- 状态定义:\(dp[i][j]\) 表示前 \(i\) 个菜品中,是否能凑出总价 \(j\)
- 状态转移:
- 不选第 \(i\) 个菜:\(dp[i][j] = dp[i-1][j]\)
- 选第 \(i\) 个菜:\(dp[i][j] = dp[i-1][j-prices[i]]\)
- 从满足条件的最小价格开始向上找第一个可以凑出的价格
代码
def solve():# 读取输入n, x = map(int, input().split())prices = list(map(int, input().split()))# 初始化dp数组dp = [[False] * 10001 for _ in range(n + 1)]dp[0][0] = True# 动态规划for i in range(n):for j in range(10001):# 不选第i个菜dp[i + 1][j] = dp[i][j]# 选第i个菜if j >= prices[i]:dp[i + 1][j] |= dp[i][j - prices[i]]# 从满足条件的最小价格开始找for total in range(x, 10001):if dp[n][total]:print(total)breakif __name__ == "__main__":solve()
import java.util.*;public class Main {public static void main(String[] args) {Scanner sc = new Scanner(System.in);// 读取输入int n = sc.nextInt();int x = sc.nextInt();int[] prices = new int[n];for (int i = 0; i < n; i++) {prices[i] = sc.nextInt();}// 初始化dp数组boolean[][] dp = new boolean[n + 1][10001];dp[0][0] = true;// 动态规划for (int i = 0; i < n; i++) {for (int j = 0; j <= 10000; j++) {// 不选第i个菜dp[i + 1][j] = dp[i][j];// 选第i个菜if (j >= prices[i]) {dp[i + 1][j] |= dp[i][j - prices[i]];}}}// 从满足条件的最小价格开始找for (int total = x; total <= 10000; total++) {if (dp[n][total]) {System.out.println(total);break;}}}
}
#include <iostream>
#include <vector>
using namespace std;int main() {// 读取输入int n, x;cin >> n >> x;vector<int> prices(n);for (int i = 0; i < n; i++) {cin >> prices[i];}// 初始化dp数组vector<vector<int>> dp(n + 1, vector<int>(10001, 0));dp[0][0] = 1;// 动态规划for (int i = 0; i < n; i++) {for (int j = 0; j <= 10000; j++) {// 不选第i个菜dp[i + 1][j] = dp[i][j];// 选第i个菜if (j >= prices[i]) {dp[i + 1][j] |= dp[i][j - prices[i]];}}}// 从满足条件的最小价格开始找for (int total = x; total <= 10000; total++) {if (dp[n][total]) {cout << total << endl;break;}}return 0;
}
算法及复杂度
- 算法:动态规划
- 时间复杂度:\(\mathcal{O}(n \cdot M)\),其中 \(n\) 是菜品数量,\(M\) 是价格上限
- 空间复杂度:\(\mathcal{O}(n \cdot M)\),用于存储 \(dp\)数组