• 【C++动态规划 多重背包】1774. 最接近目标价格的甜点成本|1701


    本文涉及知识点

    C++动态规划
    C++背包问题

    LeetCode 1774. 最接近目标价格的甜点成本

    你打算做甜点,现在需要购买配料。目前共有 n 种冰激凌基料和 m 种配料可供选购。而制作甜点需要遵循以下几条规则:
    必须选择 一种 冰激凌基料。
    可以添加 一种或多种 配料,也可以不添加任何配料。
    每种类型的配料 最多两份 。
    给你以下三个输入:
    baseCosts ,一个长度为 n 的整数数组,其中每个 baseCosts[i] 表示第 i 种冰激凌基料的价格。
    toppingCosts,一个长度为 m 的整数数组,其中每个 toppingCosts[i] 表示 一份 第 i 种冰激凌配料的价格。
    target ,一个整数,表示你制作甜点的目标价格。
    你希望自己做的甜点总成本尽可能接近目标价格 target 。
    返回最接近 target 的甜点成本。如果有多种方案,返回 成本相对较低 的一种。
    示例 1:
    输入: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 。
      示例 2:

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

    • 选择 1 号基料:成本 3
    • 选择 1 份 0 号配料:成本 1 x 4 = 4
    • 选择 2 份 1 号配料:成本 2 x 5 = 10
    • 选择 0 份 2 号配料:成本 0 x 100 = 0
      总成本:3 + 4 + 10 + 0 = 17 。不存在总成本为 18 的甜点制作方案。
      示例 3:

    输入:baseCosts = [3,10], toppingCosts = [2,5], target = 9
    输出:8
    解释:可以制作总成本为 8 和 10 的甜点。返回 8 ,因为这是成本更低的方案。
    示例 4:

    输入:baseCosts = [10], toppingCosts = [1], target = 1
    输出:10
    解释:注意,你可以选择不添加任何配料,但你必须选择一种基料。

    提示:
    n == baseCosts.length
    m == toppingCosts.length
    1 <= n, m <= 10
    1 <= baseCosts[i], toppingCosts[i] <= 104
    1 <= target <= 104

    动态规划 多重背包

    动态规划的状态表示

    价格最低的基料价格为m1,如果m1大于target,则只选择此基料。否则需要考虑的最大价格为M= target+m1。
    dp[i][m] 表示选择了一种基料,和前m种辅料后,辅料可能0到2份,能否价格为m。

    动态规划的转移方程

    枚举前置状态
    dp[i+1] = dp[i] 不选择辅料
    dp[i+1][m+tc[i]] ||= dp[i][m] 选择一份辅料
    dp[i+1][m+tc[i]*2] ||= dp[i][m] 选择两份辅料

    动态规划的初始值

    如果存在价格x的基料,则dp[0][x]=true,其它全部为false。

    动态规划的填报顺序

    i = 0 to n-1 m = 0 to M-tc[i]

    动态规划的返回值

    dp.back()[x]成立, min(abs(x-target)) 从小到大枚举x。

    代码

    核心代码

    class Solution {
    		public:
    			int closestCost(vector<int>& baseCosts, vector<int>& toppingCosts, int target) {
    				const int iMin = *min_element(baseCosts.begin(), baseCosts.end());
    				if (iMin >= target)return iMin;
    				const int M = target + (target-iMin);
    				vector<bool> pre(M + 1);
    				auto Add = [&](vector<bool>& dp,int cur) {
    					if (cur > M)return;
    					dp[cur] = true;
    				};
    				for (const auto& n : baseCosts) {
    					Add(pre, n);
    				}
    				for (const auto& n : toppingCosts) {
    					vector<bool> dp = pre;
    					for (int i = 0; i <= M; i++) {
    						if (!pre[i])continue;
    						Add(dp, i + n);
    						Add(dp, i + n*2);
    					}
    					pre.swap(dp);
    				}
    				for (int i = 0; i <= target; i++) {
    					if (pre[target - i]) { return  target - i; }
    					if (pre[target + i]) { return  target + i; }
    				}
    				return -1;
    			}
    		};
    

    单元测试

    vector<int> baseCosts, toppingCosts;
    		int target;
    		TEST_METHOD(TestMethod11)
    		{
    			baseCosts = { 1,7 }, toppingCosts = { 3,4 }, target = 10;
    			auto res = Solution().closestCost(baseCosts, toppingCosts, target);
    			AssertEx(10, res);
    		}
    		TEST_METHOD(TestMethod12)
    		{
    			baseCosts = { 2,3 }, toppingCosts = { 4,5,100 }, target = 18;
    			auto res = Solution().closestCost(baseCosts, toppingCosts, target);
    			AssertEx(17, res);
    		}
    		TEST_METHOD(TestMethod13)
    		{
    			baseCosts = { 3,10 }, toppingCosts = { 2,5 }, target = 9;
    			auto res = Solution().closestCost(baseCosts, toppingCosts, target);
    			AssertEx(8, res);
    		}
    		TEST_METHOD(TestMethod14)
    		{
    			baseCosts = { 10 }, toppingCosts = { 1 }, target = 1;
    			auto res = Solution().closestCost(baseCosts, toppingCosts, target);
    			AssertEx(10, res);
    		}
    

    扩展阅读

    我想对大家说的话
    工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
    学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
    有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
    闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
    子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
    如果程序是一条龙,那算法就是他的是睛
    失败+反思=成功 成功+反思=成功

    视频课程

    先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
    https://edu.csdn.net/course/detail/38771
    如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
    https://edu.csdn.net/lecturer/6176

    测试环境

    操作系统:win7 开发环境: VS2019 C++17
    或者 操作系统:win10 开发环境: VS2022 C++17
    如无特殊说明,本算法用**C++**实现。

  • 相关阅读:
    Python与CAD系列基础篇(六)创建块
    Django系列2-Django安装及创建项目
    nacos服务注册详解
    如何在WORDPRESS里面添加GLEGoogle Tag Manager广告跟踪代码
    【服务注册框架1】Eureka&nacos 两者的区别
    构建工具vite/webpack
    Linux:程序地址空间/虚拟地址等相关概念理解
    LeetCode 139 单词拆分
    JavaScript面向对象(2)—继承的实现
    10分钟巩固多线程基础
  • 原文地址:https://blog.csdn.net/he_zhidan/article/details/143428416