题目

https://leetcode.com/problems/shopping-offers/

题解

类似题目有:leetcode 474. Ones and Zeroes | 474. 一和零(双约束背包问题)

本题实质上是一个多约束(n<6)的背包问题,求解目标是,在背包刚好装满的情况下,希望让总的 price 最小。物品可以使用无限次。

参考左神体系班学习班第19节:剪贴纸问题(实际上没参考它,只是想到有这么个题)

给定一个字符串str,给定一个字符串类型的数组arr,出现的字符都是小写英文
arr每一个字符串,代表一张贴纸,你可以把单个字符剪开使用,目的是拼出str来
返回需要至少多少张贴纸可以完成这个任务。
例子:str= “babac”,arr = {“ba”,“c”,“abcd”}
ba + ba + c 3 abcd + abcd 2 abcd+ba 2
所以本题返回2

由于一些物品是以组合的形式给出的,所以我们先将 list 嵌套 list 转化成数组,方便索引查找。
然后,因为物品可以单独购买。为了统一方便,我们将可以单独购买的物品也转化成组合的形式,只不过让它们的系数都为 1。

如下图所示,前两行分别是单独购买 A 物品、单独购买 B 的价格,后两行是 AB 物品组合购买的价格。

然后就是经典的 暴力递归 -> 傻缓存了。本题应该是无法转化成 dp 的,因为它的状态太多了,详见 dp map 中的 key,我的处理方式是将状态压缩成了字符串。后来看题解发现,hashmap 可以直接用 list 作为 key。

还有,我这个效率超级低,(应该是我为了避免回溯而copy的数组开销比较大),删掉 import 的头文件的话,会超时(这又是 leetcode 的蜜汁特性,带头文件的话运行速度快一些),带着头文件可以 AC。

import java.util.HashMap;
import java.util.List;
import java.util.Map;class Solution {int M; // 套餐总数int N; // 物品总数public int shoppingOffers(List<Integer> price, List<List<Integer>> special, List<Integer> needs) {N = price.size();M = special.size() + price.size();// 数组化 套餐列表int[][] sp = new int[M][N + 1];for (int i = 0; i < special.size(); i++) {List<Integer> list = special.get(i);for (int j = 0; j < N + 1; j++) {sp[i][j] = list.get(j);}}for (int i = special.size(), j = 0; i < M; i++, j++) {sp[i][j] = 1;sp[i][N] = price.get(j);}// 数组化 购物清单int[] need = new int[N];for (int i = 0; i < N; i++) {need[i] = needs.get(i);}Map<String, Integer> dp = new HashMap<>();return process(sp, need, 0, dp);}// 多约束背包问题// 物品列表在special中。当前可选择的物品在cur位置,还剩余needs要买的情况下,至少需要多少costpublic int process(int[][] special, int[] needs, int cur, Map<String, Integer> dp) {// 查缓存StringBuilder key = new StringBuilder();for (int n : needs) { // 状态压缩成字符串key.append(n).append(":");}key.append(cur);if (dp.containsKey(key.toString())) return dp.get(key.toString());if (allZero(needs)) {dp.put(key.toString(), 0);return 0;}int minCost = Integer.MAX_VALUE;for (int p = cur; p < M; p++) { // 当前购买special[p]套餐for (int count = 0; canBuy(special, needs, count, p); count++) { // 购买count件p套餐int[] newNeeds = buy(special, needs, count, p);int newCost = process(special, newNeeds, p + 1, dp);if (newCost != Integer.MAX_VALUE) {minCost = Math.min(minCost, count * special[p][N + 1 - 1] + newCost);}}}// 缓存dp.put(key.toString(), minCost);return minCost;}// 当前状态下,如果继续买count件p物品,是否买了不需要的public boolean canBuy(int[][] special, int[] needs, int count, int p) {for (int k = 0; k < N; k++) {if (needs[k] - count * special[p][k] < 0) return false;}return true;}public int[] buy(int[][] special, int[] needs, int count, int p) {int[] newNeeds = new int[N];for (int k = 0; k < N; k++) {newNeeds[k] = needs[k] - count * special[p][k];}return newNeeds;}public boolean allZero(int[] needs) {for (int n : needs) {if (n != 0) return false;}return true;}}

leetcode 638. Shopping Offers | 638. 大礼包(动态规划,多约束背包问题)相关推荐

  1. LeetCode部分习题解答记录-动态规划

    LeetCode部分习题解答记录-动态规划 动态规划 120.三角形最小路径和 方法:递归+记忆化 方法2:DP 64.最小路径和 方法1:递归 方法2:DP 从终点到起点,逐步更新 从起点到终点,逐 ...

  2. 力扣刷题-python-动态规划-1 (动态规划、01背包问题、完全背包问题)

    文章目录 1.动态规划 2.简单和中等题 3.01背包问题基础 4.01背包问题 5.完全背包 6.总结 1.动态规划 动态规划 是由前一个状态推导出 贪心算法 是直接取局部最优 动态规划需要直到状态 ...

  3. 0-1背包问题 动态规划java_C#使用动态规划解决0-1背包问题实例分析

    // 利用动态规划解决0-1背包问题 using System; using System.Collections.Generic; using System.Linq; using System.T ...

  4. 算法导论——动态规划:0-1背包问题(完全解)

    2019独角兽企业重金招聘Python工程师标准>>> package org.loda.dynamic;import org.junit.Test;/*** * @ClassNam ...

  5. 经典动态规划:0-1 背包问题

    经典动态规划:0-1 背包问题 文章目录 经典动态规划:0-1 背包问题 一.题目描述 二.动规标准套路 三.题目描述 四.解法分析 五.优化 一.题目描述 就讨论最常说的 0-1 背包问题,简单描述 ...

  6. 【动态规划】简单背包问题II

    问题 J: [动态规划]简单背包问题II 时间限制: 1 Sec  内存限制: 64 MB 提交: 127  解决: 76 [提交] [状态] [讨论版] [命题人:admin] 题目描述 张琪曼:& ...

  7. 【动态规划】完全背包问题

    问题 O: [动态规划]完全背包问题 时间限制: 1 Sec  内存限制: 64 MB 提交: 151  解决: 71 [提交] [状态] [讨论版] [命题人:admin] 题目描述 话说张琪曼和李 ...

  8. 动态规划在求解背包问题中的应用(JAVA)--回溯法、记忆化法

    动态规划在求解背包问题中的应用 背包问题向来是动态规划的典型问题,给定n个重量为w1,w2,...,wn,价值为v1,v2,...,vn的物品和一个称重量为W的背包,求这些物品中最优价值的一个子集,且 ...

  9. 动态规划解决0-1背包问题详解(图文并茂)

    动态规划解决0-1背包问题 这个是网上比较好的案例,因为原文有些地方晦涩难懂,对于刚接触动态规划问题的朋友来说很不友好,所以很对地方加入了我自己的见解,也是作为我的一次学习历程. 一.问题描述: 有n ...

最新文章

  1. jQuery实例——仿京东仿淘宝列表导航菜单
  2. java 在线监测 trace_JDK自带的性能调优监测工具使用示例
  3. hashtable源码解析
  4. linux平台驱动运行空间,UIO(linux Userspace I/O子系统)用户空间设备驱动I/O技术介绍...
  5. 音乐游戏 简单模拟,字符串,cin.get,getchar,流同步(女赛)
  6. CentOS7下安装nginx1.99
  7. mac os mojave也没有增加简体拼音的专用词汇
  8. ORACLE 11g 自动内存管理
  9. n分频器 verilog_基于Verilog的分频器实现
  10. 云计算应用迁移_应用迁移策略到云
  11. 烂泥:perl中CPAN的安装
  12. ant-build.xml打包报错解决方法
  13. bzoj 1032: [JSOI2007]祖码Zuma(区间DP)
  14. STL---栈和队列
  15. java房屋出租系统
  16. Pycharm_EmmyLua断点调试Lua
  17. 手机qq怎么添加相册表情包_手机qq怎么制作表情包配文字
  18. MongoDB 清理数据
  19. 《 浅 谈 C T F 》
  20. Golang使用lxn/walk做GUI界面开发:邮件群发器

热门文章

  1. HDU - 5459 Jesus Is Here(思维+非线性递推)
  2. clob类型用java怎么存,Java 储存和读取 oracle CLOB 类型字段的实用方法
  3. 线段树HDU1698(成段更新)
  4. CEF:MFC 对话框 Demo(VS2013)
  5. Windbg教程-调试非托管程序的基本命令上
  6. 利用WinPcap技术捕获数据包
  7. WebRTC 的版本号与代码分支
  8. 2022校招百度提前批校园招聘
  9. TCP协议通讯流程(三次握手及四次挥手)
  10. 选择HLS或WebRTC需要考虑的五个因素