leetcode 638. Shopping Offers | 638. 大礼包(动态规划,多约束背包问题)
题目
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. 大礼包(动态规划,多约束背包问题)相关推荐
- LeetCode部分习题解答记录-动态规划
LeetCode部分习题解答记录-动态规划 动态规划 120.三角形最小路径和 方法:递归+记忆化 方法2:DP 64.最小路径和 方法1:递归 方法2:DP 从终点到起点,逐步更新 从起点到终点,逐 ...
- 力扣刷题-python-动态规划-1 (动态规划、01背包问题、完全背包问题)
文章目录 1.动态规划 2.简单和中等题 3.01背包问题基础 4.01背包问题 5.完全背包 6.总结 1.动态规划 动态规划 是由前一个状态推导出 贪心算法 是直接取局部最优 动态规划需要直到状态 ...
- 0-1背包问题 动态规划java_C#使用动态规划解决0-1背包问题实例分析
// 利用动态规划解决0-1背包问题 using System; using System.Collections.Generic; using System.Linq; using System.T ...
- 算法导论——动态规划:0-1背包问题(完全解)
2019独角兽企业重金招聘Python工程师标准>>> package org.loda.dynamic;import org.junit.Test;/*** * @ClassNam ...
- 经典动态规划:0-1 背包问题
经典动态规划:0-1 背包问题 文章目录 经典动态规划:0-1 背包问题 一.题目描述 二.动规标准套路 三.题目描述 四.解法分析 五.优化 一.题目描述 就讨论最常说的 0-1 背包问题,简单描述 ...
- 【动态规划】简单背包问题II
问题 J: [动态规划]简单背包问题II 时间限制: 1 Sec 内存限制: 64 MB 提交: 127 解决: 76 [提交] [状态] [讨论版] [命题人:admin] 题目描述 张琪曼:& ...
- 【动态规划】完全背包问题
问题 O: [动态规划]完全背包问题 时间限制: 1 Sec 内存限制: 64 MB 提交: 151 解决: 71 [提交] [状态] [讨论版] [命题人:admin] 题目描述 话说张琪曼和李 ...
- 动态规划在求解背包问题中的应用(JAVA)--回溯法、记忆化法
动态规划在求解背包问题中的应用 背包问题向来是动态规划的典型问题,给定n个重量为w1,w2,...,wn,价值为v1,v2,...,vn的物品和一个称重量为W的背包,求这些物品中最优价值的一个子集,且 ...
- 动态规划解决0-1背包问题详解(图文并茂)
动态规划解决0-1背包问题 这个是网上比较好的案例,因为原文有些地方晦涩难懂,对于刚接触动态规划问题的朋友来说很不友好,所以很对地方加入了我自己的见解,也是作为我的一次学习历程. 一.问题描述: 有n ...
最新文章
- jQuery实例——仿京东仿淘宝列表导航菜单
- java 在线监测 trace_JDK自带的性能调优监测工具使用示例
- hashtable源码解析
- linux平台驱动运行空间,UIO(linux Userspace I/O子系统)用户空间设备驱动I/O技术介绍...
- 音乐游戏 简单模拟,字符串,cin.get,getchar,流同步(女赛)
- CentOS7下安装nginx1.99
- mac os mojave也没有增加简体拼音的专用词汇
- ORACLE 11g 自动内存管理
- n分频器 verilog_基于Verilog的分频器实现
- 云计算应用迁移_应用迁移策略到云
- 烂泥:perl中CPAN的安装
- ant-build.xml打包报错解决方法
- bzoj 1032: [JSOI2007]祖码Zuma(区间DP)
- STL---栈和队列
- java房屋出租系统
- Pycharm_EmmyLua断点调试Lua
- 手机qq怎么添加相册表情包_手机qq怎么制作表情包配文字
- MongoDB 清理数据
- 《 浅 谈 C T F 》
- Golang使用lxn/walk做GUI界面开发:邮件群发器