题目1 : 满减优惠
时间限制:
10000ms
单点时限:
1000ms
内存限制:
256MB
描述
最近天气炎热,小Ho天天宅在家里叫外卖。他常吃的一家餐馆一共有N道菜品,价格分别是A1, A2, ... AN元。并且如果消费总计满X元,还能享受优惠。小Ho是一个不薅羊毛不舒服斯基的人,他希望选择若干道不同的菜品,使得总价在不低于X元的同时尽量低。
你能算出这一餐小Ho最少消费多少元吗?
输入
第一行包含两个整数N和X,(1 <= N <= 20, 1 <= X <= 100)
第二行包含N个整数A1, A2, ..., AN。(1 <= Ai <= 100)
输出
输出最少的消费。如果小Ho把N道菜都买了还不能达到X元的优惠标准,输出-1。
好久没有写题了,不得不说csdn这个编辑页面真的是越改越差。
这道题我用了动规跟dfs做,结果dfs只有70分,我也不太懂,都po出来吧。动规好理解,就是01背包问题,这里再梳理一下这类型的问题。
01背包:动态规划之01背包问题(最易理解的讲解)
大概意思就是:f [ I, j ] = max { ( f [ i-1, j - Wi ] + Pi)(其中 j >= Wi ) , f [ I-1, j ] } :f代表背包里有 I 个物体,其重量为 j 时的价值,其中每个物品的重量为Wi,价值为Pi。一般遍历就是从 i : 0-->n,j :0 --> sum(Wi),(初始值都为零)也视情况而定。
int main(){
int sum = 0;
cin>>n>>x;
int dp[200] = {0};
for(int i = 0; i<n; i++){
scanf("%d", &a[i]);
sum += a[i];
}
int d = sum-x;
if(d < 0) printf("-1\n");
else if(d == 0) printf("%d\n", x);
else{
int out = -1;
for(int i = 0; i<n; i++){
for(int j = d; j>=0; j--){
dp[j] = max(dp[j], dp[j-a[i]]+a[i]);
out = max(dp[j], out);
}
}
printf("%d", out);
}
return 0;
}
因为这个对物品的个数不敏感,所以不用dp[i,j],只用dp[i]即可。先将所有的物体全放进去,然后在物品总重大于x(d>0)的情况下能拿多少就拿多少。之前一直想着先动规出在总重小于x的时候拿到最大,然后再加上任意其他看最小,可行性很低,换个思路就简单多了。
dfs我也不知道哪里错了,就是排列组合的说。
int a[200] = {0};
int n, x;
int dfs(int b, int sum){
int out = 1000000000;
if(sum >= x){
return sum;
}
for(int i = b+1; i<n; i++){
out = min(out, dfs(i, sum+a[i]));
}
return out;
}
int _main() {
int sum = 0;
int out = 1000000000;
cin>>n>>x;
for(int i = 0; i<n; i++){
scanf("%d", &a[i]);
sum += a[i];
}
if(sum < x){
printf("-1\n");
return 0;
}
sort(a, a+n, [](int x1, int x2){return x1 < x2;});
for(int i = 0; i<n; i++){
out = min(out, dfs(i, a[0]));
}
printf("%d\n", out);
return 0;
}