leeode.5690. 最接近目标价格的甜点成本

题目

你打算做甜点,现在需要购买配料。目前共有 n 种冰激凌基料和 m 种配料可供选购。而制作甜点需要遵循以下几条规则:

必须选择 一种 冰激凌基料。
可以添加 一种或多种 配料,也可以不添加任何配料。
每种类型的配料 最多两份 。
给你以下三个输入:

baseCosts ,一个长度为 n 的整数数组,其中每个 baseCosts[i] 表示第 i 种冰激凌基料的价格。
toppingCosts,一个长度为 m 的整数数组,其中每个 toppingCosts[i] 表示 一份 第 i 种冰激凌配料的价格。
target ,一个整数,表示你制作甜点的目标价格。
你希望自己做的甜点总成本尽可能接近目标价格 target 。

返回最接近 target 的甜点成本。如果有多种方案,返回 成本相对较低 的一种。

示例一

输入:baseCosts = [1,7], toppingCosts = [3,4], target = 10
输出:10
解释:考虑下面的方案组合(所有下标均从 0 开始):

  • 选择 1 号基料:成本 7
  • 选择 1 份 0 号配料:成本 1 x 3 = 3
  • 选择 0 份 1 号配料:成本 0 x 4 = 0
    总成本:7 + 3 + 0 = 10 。

思路分析

  • 这道题转换成多重背包的背包问题。多重背包问题的模板如下
for(int i=1;i<=n;i++)//枚举物品
	for(int j=V;j>=0;j--)//枚举体积
		for(int k=1;k<=num[i],k++)
			if(j-k*c[i]>=0)//判断能否装下.
				f[j]=max(f[j],f[j-k*c[i]]+k*w[i]);
  • 因为每种配料最多装两次,因此我们模板中的k的上界是2.
  • 但是这道题比较坑的有三点。
    1.就是在最终拼成的数值需要离target最近,也就是说完全可以大于target,因此其实我们的上限应该去找2target。也就是j的循环应该是2target。例如对于测试用例[4],[8],target=9,此时答案应该是12而不是4
    2.其次这道题比较坑的一点是必须要至少有一种基料,也就是对于测试用例[100],[1],[1]来说,答案应该是100.对于这种测试用例来说,上线应该是基料的最大值+配料的最大值;
    3.如果target+x和target-x都可以配成,返回的是target-x.对于测试用例[3,10],[2,5],9来说返回的是8而不是10.

代码

class Solution {
public:
    int closestCost(vector<int>& baseCosts, vector<int>& toppingCosts, int target) {
        int m = toppingCosts.size(), maxn = 0x3f3f3f3f;
        vector<bool> bag(20001 , false);//开数组的大小为了避免坑点1,2
        for(auto k : baseCosts) bag[k] = true;
        for(int i = 0 ;i < m;i++){
            for(int j = 20000; j >= 0;j--){ 
                for(int k = 0;k <= 2;k++){
                    int p = j - k * toppingCosts[i];
                    if(p >= 0) bag[j] = bag[j] || bag[p];  
                }
            // 如果在这里就判断,那么不满足坑点3
            // if(bag[j] && abs(j - target) < abs(maxn - target))   maxn = j;
            }
        }
        for(int i = 0;i < bag.size();i++)
            if(bag[i] && abs(i - target) < abs(maxn - target))   maxn = i;         
        return maxn;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值