第八十八天 --- 力扣638. 大礼包

  • 题目一
    • 思路:回溯法
    • 代码
      • 无剪枝的回溯
      • 剪枝优化
  • Sum Up

题目一

力扣:力扣638. 大礼包


思路:回溯法

1、我们先不考虑礼包,直接去买东西,就是物品数量*物品价格,但是现在有优惠了,允许你买礼包。同一种礼包可一直买,也可以不同种礼包搭配。
2、现在我们的需求在needs中存着,我有两种选择,直接购买,买一种礼包。
<1>先算出直接买用多少钱。
<2>在众多礼包中选择符合要求的一个礼包,因为很多礼包,就得遍历礼包集合。我买了这个礼包,减少了一定的需求,那么花的钱就是,这个礼包花的钱+完成剩下的需求用的钱(把新的需求传下去,当后面算完就能回溯回来一个值,这个就是回溯思想)
<3>读题,我们要找到花钱最少是多少,所以要在买礼包和直接买之间找一个最小值作为答案。
3、“2”中分析了一次决策的过程,我们想,因为礼包之间可以任意搭配,所以礼包的决策会有很多次。一次选一个礼包,就完成了一次决策,那么就更新需求数组,因为每一次决策过程都一致,所以DFS实现,一个函数是一次决策,最后就能暴力枚举出来所有可能。
4、如果上述过程没明白,自己画一棵选择树,大部分DFS+回溯的过程都能在选择树上分析的很清楚,所以只要树整明白了,那么这个题就拿下了。

代码

细节:一定要注意,如果礼包中卖的物品多余所求,则不能买,所以要加以判断。

无剪枝的回溯

1、无剪枝,考虑所有可能的礼包。

class Solution {public:vector<int> price;vector<vector<int>> special;vector<int> needs;int buyBySpecialOffers(vector<int> n) {int ans = 0;//这层决策,要花的最少钱for (int i = 0; i < n.size(); i++) {ans += price[i] * n[i];//先考虑不买礼包}int size_special = special.size();for (int i = 0; i < size_special; i++) {//买礼包,枚举礼包vector<int> tmp(n);//复制一遍需求,因为每次都是假设买这个礼包,会改变需求,一旦这个礼包不能买,就会导致数据损失int size1 = special[i].size();int price = special[i][size1 - 1];//礼包价格bool is_valid = true;//礼包能不能买for (int j = 0; j < size1 - 1; j++) {if (special[i][j] > n[j]) {//v出现了提供物品数大于需求is_valid = false;//不能买了break;}tmp[j] -= special[i][j];//假设能买,更新需求于临时需求数组}if (is_valid) {price += buyBySpecialOffers(tmp);//利用回溯思想,本礼包钱,加上剩下需求的钱ans = min(ans, price);}else {continue;}}return ans;}int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {this->price = price;this->special = special;this->needs = needs;return buyBySpecialOffers(needs);}
};

代码已经通过力扣OJ测试
(多次测试得到最短时间为):

剪枝优化

1、buyBySpecialOffers回溯函数并未改变
2、商家不是慈善家,有很多坑人的礼包:
<1>礼包只收钱,不卖你物品。属于抢劫行为的礼包,直接干掉就行。(极端情况,也要考虑进去)
<2>黑心商家,买了礼包反而更贵

class Solution {public:vector<int> price;vector<vector<int>> special;vector<int> needs;int buyBySpecialOffers(vector<int> n) {//注释同上,此函数没变int ans = 0;for (int i = 0; i < n.size(); i++) {ans += price[i] * n[i];}int size_special = special.size();for (int i = 0; i < size_special; i++) {vector<int> tmp(n);int size1 = special[i].size();int price = special[i][size1 - 1];bool is_valid = true;for (int j = 0; j < size1 - 1; j++) {if (special[i][j] > n[j]) {is_valid = false;break;}tmp[j] -= special[i][j];}if (is_valid) {price += buyBySpecialOffers(tmp);ans = min(ans, price);}else {continue;}}return ans;}int shoppingOffers(vector<int>& price, vector<vector<int>>& special, vector<int>& needs) {this->price = price;this->needs = needs;//把坑人的大礼包去掉(剪枝):一件物品没有还要钱;买了礼包更贵int n1 = price.size();//这块操作读题就行vector<vector<int>> tmp;for (vector<int> item : special) {//数据预处理int cnt = 0, cnt_price = 0;//分别是统计卖出物品数,和按照原价买多少钱for (int i = 0; i < n1; i++) {cnt += item[i];cnt_price += item[i] * price[i];}if (cnt > 0 && item[n1] < cnt_price) {tmp.push_back(item);//只保留有效礼包}}this->special = tmp;return buyBySpecialOffers(needs);}
};

代码已经通过力扣OJ测试
(多次测试得到最短时间为):

Sum Up

这种回溯思路其实就是暴力枚举所有可能的选取礼包方案,一定要注意题目约定的数据量大小,一般就是<=10^2这个数量级的时候,即小数据量的时候,这个方法才可以。数据量上1000就不要用这个算法了,就用DP。

力扣638. 大礼包(回溯法+剪枝优化)相关推荐

  1. 【力扣638】 大礼包问题 JAVA全过程详解,绝对易懂

    [前言]:本文讲解[力扣638 大礼包]的[动态规划]方法及其[记忆化搜索]的改进. 一.题目描述 在 LeetCode 商店中,有 n 件在售的物品.每件物品 i 都有对应的价格,也有一些大礼包以优 ...

  2. 20210325:力扣递归,回溯类型题目合集

    力扣递归,回溯类型题目合集 题目 思路与算法 代码实现 写在最后 题目 子集 2. 90. 子集 II 3. 40. 组合总和 II 4. 22. 括号生成 思路与算法 子集:注释的很详细,递归生成子 ...

  3. 图的m着色问题——回溯法及其优化(变量排序MRV, 值排序MCV, 前向检查ForwardChecking, 智能回溯, 边相容,K阶相容)python C++实现

    文章目录 图的m着色问题背景 背景知识 问题描述 回溯法的原理及其实现 回溯法基本思想 朴素回溯法解决图的m着色问题 回溯优化策略 回溯法优化--变量排序MRV 回溯法优化--值排序MCV 回溯法优化 ...

  4. 递归与回溯5:剪枝优化

    我们说过,回溯法虽然是暴力搜索,但也有时候可以有点剪枝优化一下的,主要就是去掉那些不必要的递归,从而提高执行效率.例如假如有五个男孩子都和一个女生说要厮守终生.她会和这五个人都先过一辈子再确定谁会真正 ...

  5. 回溯法(深度优先)剪枝和分支限界法(宽度优先)剪枝对比:01背包问题

    限界函数: CurValue + rest <= BestValue 回溯法(深度优先)剪枝 # 递归方式 class pack_01_back_prune_test: def __init__ ...

  6. 消消乐实验回溯法(深大算法实验3)报告+代码

    实验代码 + 报告资源: 链接: https://pan.baidu.com/s/1CuuB07rRFh7vGQnGpud_vg 提取码: ccuq 目录 写在前面 实验要求 求解问题的算法原理描述 ...

  7. 彻底搞懂回溯法(本文真的很详细)

    目录 回溯法理论基础 组合问题 组合问题 组合总和 组合总和(一) 组合总和(二) 组合总和(三)(本题去重特别重要) 多个集合求组合 切割问题 子集问题 子集问题(一) 子集问题(二) 递增子序列 ...

  8. [剑指offer]面试题第[38]题[JAVA][字符串的排列][回溯法]

    [问题描述][中等] 输入一个字符串,打印出该字符串中字符的所有排列. 你可以以任意顺序返回这个字符串数组,但里面不能有重复元素.示例: 输入:s = "abc" 输出:[&quo ...

  9. 力扣编程题-解法汇总

    一.力扣链接: 题库 - 力扣 (LeetCode) 全球极客挚爱的技术成长平台 备注:以后每个工作日从前往后刷一道题,然后再加一道每日新题.每天两道题. 二.模版: 标题: 力扣解法汇总5-正则表达 ...

最新文章

  1. Java学习总结:56(Stack子类)
  2. 【怎样写代码】函数式编程 -- Lambda表达式(四):Lambda表达式与Expression树
  3. 四川大学java试题_四川大学2013年计算机(软件)学院Java语言程序设计期末考试试题B卷...
  4. 电大计算机2019作业,【电大题】2019年最新国家开 放大学电大《人文英语2、3、》网络核心课形考网考作业两套汇编附全答案.docx...
  5. 系统管理员设置了系统策略,禁止进行此安装
  6. Git 技术篇-git切换工作空间,git设置默认进入空间,git初始化工作空间
  7. JVM 调优系列之图解垃圾回收
  8. 【转】vivado18.3的安装 安装教程
  9. 求有向图的简单路径_2020福建农信社招聘-关键路径
  10. python井字棋游戏人机对战_用Python做一个井字棋小游戏
  11. Node 实现 AES 加密,结果输出为“byte”。
  12. 软件测试 学习之路 linux 基础命令 (三)
  13. memcached 分布式锁 java_分布式锁的三种实现方式
  14. vue项目实现记住密码功能
  15. babel css3新特性_css3 transform属性多值的顺序问题
  16. C# 添加服务引用。
  17. 2017年二级计算机c真题语言,2017全国计算机二级C考试真题
  18. 电机与拖动课程最全思维导图笔记
  19. 黎曼猜想到底是什么意思?
  20. LA4670 Dominating Patterns(AC自动机)

热门文章

  1. 城市道路注记抽稀方法探讨
  2. javascript知识点汇总 - 十大思维导图
  3. 大企业HR透露:什么样的应聘者更易被青睐!
  4. Java程序的运行过程(执行流程)分析
  5. c语言扫雷显示坐标周围,C语言实现扫雷 - osc_kas7094m的个人空间 - OSCHINA - 中文开源技术交流社区...
  6. 成为构架师必知的Vue目录结构和构建规范,恩师王红元的蘑菇街项目❤
  7. 计算机主板上电时序图,主板上电时序图ppt课件.ppt
  8. linux xz 解压initrd.img,initrd.img的压缩(制作)及解压的过程
  9. Transformer入门学习
  10. springboot整合redis实现HyperLogLog统计文章浏览量使用过期策略完成数据库同步