题目:链接:https://www.nowcoder.com/questionTerminal/5d2405da8d364eafbaca1de9bc2a0d4e?answerType=1&f=discussion
来源:牛客网
[编程题]代金券组合
- 热度指数:766 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
近期某商场由于周年庆,开启了“0元购”活动。活动中,消费者可以通过组合手中的代金券,实现0元购买指定商品。
聪明的小团想要用算法来帮助他快速计算:对于指定价格的商品,使用代金券凑出其价格即可,但所使用的代金券总面额不可超过商品价格。由于代金券数量有限,使用较少的代金券张数则可以实现价值最大化,即最佳优惠。
假设现有100元的商品,而代金券有50元、30元、20元、5元四种,则最佳优惠是两张50元面额的代金券;而如果现有65元的商品,则最佳优惠是两张30元代金券以及一张5元代金券。
请你帮助小团使用一段代码来实现代金券计算。
输入描述:
多组输入输出,读到s=0时结束
输入可以有多个测试样例,每个测试由两行组成。
其中第一行包含一个整数P,表示商品的价格,1≤P≤10000;输入P为0时表示结束。
第二行包含若干整数,使用空格分割。其中第一个整数N(1≤N≤20)表示有多少种代金券,其后跟随M个整数,表示手中持有的代金券面额(1≤N≤1000),每种代金券数量不限。
输出描述:
找到最少张数的代金券,使其面额恰好等于商品价格。输出所使用的代金券数量;
如果有多个最优解,只输出其中一种即可;
如果无解,则需输出“Impossible”。
示例1
输入
65 4 50 30 20 5 0
输出
3以上,就是全部题目,相信学过DP的朋友们,都能看出来是个DP的动态规划题目,引入一个数组F[n]来记录0——cash元的最优解有几张(n 就是遍历 0 - cash 的,因为你最终的答案是建立在cash之前的金额上的),想要遍历出最优解首先得把F[n] 初始一个很大的值,在遍历中用min()函数,如果遇到最优解的方法将最优解的小值替换掉较大的解。
如果所有0-cash所有的钱都遍历完了,但f[cash] 还等于你初始设置的呢个数,则代表没有代金券能刚好抵消商品价格,就是没有最优的解,所以输出Impossible,反之,输出f[cash]最优解。
#include<stdio.h>
#include<string.h> #include<iostream> #include<algorithm> using namespace std; int main(){ int cash,s; int coins[21]; while(~scanf("%d",&cash)&& cash != 0) { scanf("%d",&s); for(int i = 0 ; i < s ; i ++) { scanf("%d",&coins[i]); } sort(coins,coins+s); int F[10000]; for(int i = 0 ; i <= cash ; i ++){ F[i] = cash +1; // 这一块就是为了初始值,设一个很大的数字就行 } F[0] = 0; // 在0 元时,最优解就是0张; for(int j = 0 ; j <= cash ; j ++) //枚举金钱数
{ for(int k = 0 ; k < s ; k ++) { if(j < coins[k]) // 因为代金券不能大于金钱额度,所以遍历到直接跳出了,毕竟经过排序,后面的代金券的值都大于目前代金券的值。 break; else F[j] = min(F[j-coins[k]]+1 ,F[j]); //反之,如果小于,则将金钱额度-目前这个代金券 得到的是上一个没用这次代金券的值, 将使用本次代金券的值 和 不使用代金券的值 相对比,取最优解。+1的原因是F数组里存的最优解是几张,如果使用这次代金券则张数必加1 } } if(F[cash] == cash+1) cout << "Impossible" << endl; else cout << F[cash] << endl; } }