【动态规划】饭卡
题目
电子科大本部食堂的饭卡有一种很诡异的设计,即在购买之前判断余额。如果购买一个商品之前,卡上的剩余金额大于或等于5元,就一定可以购买成功(即使购买后卡上余额为负),否则无法购买(即使金额足够)。所以大家都希望尽量使卡上的余额最少。
某天,食堂中有n种菜出售,每种菜可购买一次。已知每种菜的价格以及卡上的余额,问最少可使卡上的余额为多少。
输入输出
Input多组数据。对于每组数据:
第一行为正整数n,表示菜的数量。n<=1000。
第二行包括n个正整数,表示每种菜的价格。价格不超过50。
第三行包括一个正整数m,表示卡上的余额。m<=1000。
n=0表示数据结束。
Output对于每组输入,输出一行,包含一个整数,表示卡上可能的最小余额。
Sample Input
1
50
5
Output
-45
Sample Input
10
1 2 3 2 1 1 2 3 2 1
50
Sample Output
32
分析
01背包问题,,我们先把卡上的余额m 减去5,应该保证最后有5元买个最贵的。
对读入的价格进行小到大排序, 因为每种菜只能买一次,所以先枚举到n-1,保证最后5元还有最大的可以买。
这是因为如果不这样,不一定含有最大的价格的那个dp【】就是最大,而且专门留下5元就是为了买个最大价格的
代码
#include<iostream>
#include<algorithm>
using namespace std;
int a[1010];
int dp[50050];
int main(){
int n,m;
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n);
cin>>m;
if(m< 5){
cout<<m<<endl;
return 0;
}
m = m-5;
for(int i=0;i<n-1;i++){ //0 到 n-1
for(int j=m;j>=a[i];j--){
dp[j] = max(dp[j -a[i]] + a[i], dp[j]);
}
}
cout<<m+5 -dp[m] -a[n-1]; //卡上本来的钱 减掉dp[m] 时最大的钱 再减 价格最大的那个 就是卡剩下的钱
return 0;
}
// #include<iostream>
// using namespace std;
// #include<algorithm>
// const int N = 2e3 +9;
// int a[1010],f[N];
// int main(){
// int n,m;
// cin>>n;
// for(int i=0;i<n;i++){
// cin>>a[i];
// }
// cin>>m;
// f[0] = 1;
// sort(a,a+n);
// int ma = 0;
// for(int i=0;i<n;i++){
// for(int j=m-5;j>=0;j--){
// if(f[j]){
// f[j + a[i] ] = 1;
// ma = max(ma,j+a[i]);
// }
// }
// }
// cout<< m -ma<<endl;
// return 0;
// }