当前位置: 首页 > news >正文

40.讲初识动态规划:如何巧妙解决“双十一”购物时的凑单问题

文章目录

  • 1. 动态规划学习路线
  • 2. 0-1背包问题
  • 3. 0-1背包问题升级版

问题: 满200元减50元”。购物车中有n个(n>100)想买的商品,希望从里面选几个,在凑够满减条件的前提下,让选出来的商品价格总和最大程度地接近满减条件(200元),如何解决?

1. 动态规划学习路线

  • 初识动态规划

通过两个非常经典的动态规划问题模型,认识为什么需要动态规划,动态规划解决方法如何演化。

  • 动态规划理论

总结动态规划适合解决的问题的特征,以及动态规划解题思路。除此之外,将贪心、分治、回溯、动态规划这四种算法思想放在一起,对比分析它们各自的特点以及适用的场景。

  • 动态规划实战

实战解决三个非常经典的动态规划问题。

2. 0-1背包问题

// 回溯算法实现。注意:我把输入的变量都定义成了成员变量。
private int maxW = Integer.MIN_VALUE; // 结果放到maxW中
private int[] weight = {22463};  // 物品重量
private int n = 5; // 物品个数
private int w = 9; // 背包承受的最大重量
public void f(int i, int cw) { // 调用f(0, 0)
  if (cw == w || i == n) { // cw==w表示装满了,i==n表示物品都考察完了
    if (cw > maxW) maxW = cw;
    return;
  }
  f(i+1, cw); // 选择不装第i个物品
  if (cw + weight[i] <= w) {
    f(i+1,cw + weight[i]); // 选择装第i个物品
  }
}

找规律:
在这里插入图片描述
重复解:

private int maxW = Integer.MIN_VALUE; // 结果放到maxW中
private int[] weight = {22463};  // 物品重量
private int n = 5; // 物品个数
private int w = 9; // 背包承受的最大重量
private boolean[][] mem = new boolean[5][10]; // 备忘录,默认值false
public void f(int i, int cw) { // 调用f(0, 0)
  if (cw == w || i == n) { // cw==w表示装满了,i==n表示物品都考察完了
    if (cw > maxW) maxW = cw;
    return;
  }
  if (mem[i][cw]) return; // 重复状态
  mem[i][cw] = true; // 记录(i, cw)这个状态
  f(i+1, cw); // 选择不装第i个物品
  if (cw + weight[i] <= w) {
    f(i+1,cw + weight[i]); // 选择装第i个物品
  }
}

二维数组states[n][w+1],来记录每层可以达到的不同状态。

在这里插入图片描述

weight:物品重量,n:物品个数,w:背包可承载重量
public int knapsack(int[] weight, int n, int w) {
  boolean[][] states = new boolean[n][w+1]; // 默认值false
  states[0][0] = true;  // 第一行的数据要特殊处理,可以利用哨兵优化
  states[0][weight[0]] = true;
  for (int i = 1; i < n; ++i) { // 动态规划状态转移
    for (int j = 0; j <= w; ++j) {// 不把第i个物品放入背包
      if (states[i-1][j] == true) states[i][j] = states[i-1][j];
    }
    for (int j = 0; j <= w-weight[i]; ++j) {//把第i个物品放入背包
      if (states[i-1][j]==true) states[i][j+weight[i]] = true;
    }
  }
  for (int i = w; i >= 0; --i) { // 输出结果
    if (states[n-1][i] == true) return i;
  }
  return 0;
}

优化:boolean[][] states是二维,比较耗内存,可以用一维替代

public static int knapsack2(int[] items, int n, int w) {
  boolean[] states = new boolean[w+1]; // 默认值false
  states[0] = true;  // 第一行的数据要特殊处理,可以利用哨兵优化
  states[items[0]] = true;
  for (int i = 1; i < n; ++i) { // 动态规划
    for (int j = w-items[i]; j >= 0; --j) {//把第i个物品放入背包
      if (states[j]==true) states[j+items[i]] = true;
    }
  }
  for (int i = w; i >= 0; --i) { // 输出结果
    if (states[i] == true) return i;
  }
  return 0;
}

3. 0-1背包问题升级版

刚刚讲的背包问题,只涉及背包重量和物品重量。我们现在引入物品价值这一变量。对于一组不同重量、不同价值、不可分割的物品,我们选择将某些物品装入背包,在满足背包最大重量限制的前提下,背包中可装入物品的总价值最大是多少呢?

  • 回溯
private int maxV = Integer.MIN_VALUE; // 结果放到maxV中
private int[] items = {22463};  // 物品的重量
private int[] value = {34896}; // 物品的价值
private int n = 5; // 物品个数
private int w = 9; // 背包承受的最大重量
public void f(int i, int cw, int cv) { // 调用f(0, 0, 0)
  if (cw == w || i == n) { // cw==w表示装满了,i==n表示物品都考察完了
    if (cv > maxV) maxV = cv;
    return;
  }
  f(i+1, cw, cv); // 选择不装第i个物品
  if (cw + weight[i] <= w) {
    f(i+1,cw+weight[i], cv+value[i]); // 选择装第i个物品
  }
}

在这里插入图片描述

public static int knapsack3(int[] weight, int[] value, int n, int w) {
  int[][] states = new int[n][w+1];
  for (int i = 0; i < n; ++i) { // 初始化states
    for (int j = 0; j < w+1; ++j) {
      states[i][j] = -1;
    }
  }
  states[0][0] = 0;
  states[0][weight[0]] = value[0];
  for (int i = 1; i < n; ++i) { //动态规划,状态转移
    for (int j = 0; j <= w; ++j) { // 不选择第i个物品
      if (states[i-1][j] >= 0) states[i][j] = states[i-1][j];
    }
    for (int j = 0; j <= w-weight[i]; ++j) { // 选择第i个物品
      if (states[i-1][j] >= 0) {
        int v = states[i-1][j] + value[i];
        if (v > states[i][j+weight[i]]) {
          states[i][j+weight[i]] = v;
        }
      }
    }
  }
  // 找出最大值
  int maxvalue = -1;
  for (int j = 0; j <= w; ++j) {
    if (states[n-1][j] > maxvalue) maxvalue = states[n-1][j];
  }
  return maxvalue;
}

时间复杂度是O(nw),空间复杂度也是O(nw)。

相关文章:

  • 信息学奥赛中的STL(标准模板库)--2022.09.30
  • 量子力学摘记3
  • C++11详解
  • vue3+TS实现简易组件库
  • 【深度学习100例】—— Python+OpenCV+MediaPipe实时人流检测 | 第3例
  • Mysql和ES数据同步方案汇总
  • Java / Tensorflow - API 调用 pb 模型使用 GPU 推理
  • 【CSS】精灵图 背景图 阴影 过渡
  • 【设计模式】【第五章】【开具增值税发票】【建造者模式 + 原型模式】
  • 【关于Linux中权限管理】
  • Opencv项目实战:11 使用Opencv高亮显示文本检测
  • 零基础转行,入职军工类测试方向,月薪10K | 既然选择了,就要全力以赴
  • python字典与集合还有数据类型转换
  • CH559L单片机ADC多通道采样数据串口打印案例
  • 2022保研夏令营/预推免记录:浙大计院直博/西湖电子直博/南大软院/厦大信院
  • E-HPC支持多队列管理和自动伸缩
  • ES10 特性的完整指南
  • Java多态
  • java取消线程实例
  • Linux中的硬链接与软链接
  • PHP面试之三:MySQL数据库
  • redis学习笔记(三):列表、集合、有序集合
  • springboot_database项目介绍
  • SQLServer插入数据
  • Vue.js-Day01
  • 百度小程序遇到的问题
  • 高度不固定时垂直居中
  • 看完九篇字体系列的文章,你还觉得我是在说字体?
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 如何编写一个可升级的智能合约
  • 山寨一个 Promise
  • 实战|智能家居行业移动应用性能分析
  • 算法-插入排序
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • %check_box% in rails :coditions={:has_many , :through}
  • (1)安装hadoop之虚拟机准备(配置IP与主机名)
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (floyd+补集) poj 3275
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (Python) SOAP Web Service (HTTP POST)
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (附源码)springboot助农电商系统 毕业设计 081919
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (三)uboot源码分析
  • (一)Dubbo快速入门、介绍、使用
  • (最优化理论与方法)第二章最优化所需基础知识-第三节:重要凸集举例
  • ./configure,make,make install的作用(转)
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .htaccess配置常用技巧
  • .L0CK3D来袭:如何保护您的数据免受致命攻击
  • .NET Standard 的管理策略
  • .net网站发布-允许更新此预编译站点