NUIST 9th 校赛 P4
题目描述
每天我们都会思考一个令人纠结的难题:晚上吃什么。你打开手机想点个外卖,发现自己有一张满减优惠券快要过期了。
你选择了一家餐厅,这家餐厅一共有 N 道菜品,价格分别是 A1, A2, … , AN 元。只要消费满 X 元,就可以用掉这张优惠券。
你希望选择若干道 不同 的菜品,使得总价在不低于 X 元的同时尽量低。
为了用掉这张优惠券,你最少需要消费多少元?
输入描述
题目包含多组测试数据。第一行包括一个正整数 T,代表测试数据的组数。
接下来的输入,对于每组测试数据:
第一行包含两个整数 N 和 X (1 ≤ N ≤ 20, 1 ≤ X ≤ 100)
第二行包含 N 个整数 A1, A2, … , AN (1 ≤ Ai ≤ 100)
输出描述
对于每组测试数据,输出最少的消费。如果你把 N 道菜都买了还不能达到 X 元的优惠标准,输出 -1。
样例输入
2
10 50
9 9 9 9 9 9 9 9 9 8
3 30
9 9 9
样例输出
53
-1
这道题是一道DP。
状态转移方程 F[i][j] = min(f[i-1][j],f[i-1][j-value[i]] )+ value[i]
f[i][j] = min(f[i-1][j] ,value[i])
关键在于它是如何体现F[i][j] 一定不少于X元
把所有的值初始化为BigINT,j = 0 时 为 0,用递推思想理解即可。假设j不存在,那么j+value[i],也一定不存在,因为,前面的数无法到达j,j+value[i],也到达不了。理解了这个思想,很容易就想出:
for(int i = 1;i<=n;i++){
for(int j = 1;j<=x;j++){
if(j>=a[i][j]){
dp[i][j] = min(dp[i-1][j],dp[i-1][j-a[i]]+a[i]);
}
else{
dp[i][j] = min(dp[i-1][j],a[i]);
}
}
}
空间复杂度为O(nx)时间复杂度(nx)
但是空间可以做出优化
for(int i = 1;i<=n;i++){
for(int j = x;j>=1;j--){
if(j>=a[i]){
dp[j] = min(dp[j],dp[j-a[i]]+a[i]);
}
else{
dp[j] = min(dp[j],a[i]);
}
}
}
区别在于j要从后往前