参考:

背包九讲——哔哩哔哩

背包九讲


01背包问题

描述:

有N件物品和一个容量为V的背包。

第i件物品的体积是vi,价值是wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包流量,且总价值最大。

二维动态规划

f[i][j] 表示只看前i个物品,总体积是j的情况下,总价值最大是多少。 result = max(f[n][0~V]) f[i][j]:

  • 不选第i个物品:f[i][j] = f[i-1][j];

  • 选第i个物品:f[i][j] = f[i-1][j-v[i]] + w[i](v[i]是第i个物品的体积) 两者之间取最大。 初始化:f[0][0] = 0 (啥都不选的情况,不管容量是多少,都是0?)

代码如下:

n, v = map(int, input().split())
goods = []
for i in range(n):
goods.append([int(i) for i in input().split()]) # 初始化,先全部赋值为0,这样至少体积为0或者不选任何物品的时候是满足要求
dp = [[0 for i in range(v+1)] for j in range(n+1)] for i in range(1, n+1):
for j in range(1,v+1):
dp[i][j] = dp[i-1][j] # 第i个物品不选
if j>=goods[i-1][0]:# 判断背包容量是不是大于第i件物品的体积
# 在选和不选的情况中选出最大值
dp[i][j] = max(dp[i][j], dp[i-1][j-goods[i-1][0]]+goods[i-1][1]) print(dp[-1][-1])

一维动态优化

从上面二维的情况来看,f[i] 只与f[i-1]相关,因此只用使用一个一维数组[0~v]来存储前一个状态。那么如何来实现呢?

第一个问题:状态转移

假设dp数组存储了上一个状态,那么应该有:

dp[i] = max(dp[i] , dp[i-v[i]]+w[i])

max函数里面的dp[i]代表的是上一个状态的值。

第二个问题:初始化

这里开始初始化一个长度为V+1一维数组,选取0个物品时,体积为0~V时的最大价值(值全部为0)。

第三个问题:递推关系

试想一下,我要保证求取第i个状态时,用到一维数组中的值是第i-1个状态的。如果,我从前往后推,那么当我遍历到后面时,我用到的状态就是第i个状态而不是第i-1个状态。比如:

dp[i] = max(dp[i] , dp[i-v[i]]+w[i])

这里的dp[i-v[i]]是已经重新赋值的,而不是上一个状态的值,所以这样是错误的。因此,我们要从后往前推

n, v = map(int, input().split())
goods = []
for i in range(n):
goods.append([int(i) for i in input().split()]) dp = [0 for i in range(v+1)] for i in range(n):
for j in range(v,-1,-1): # 从后往前
if j >= goods[i][0]:
dp[j] = max(dp[j], dp[j-goods[i][0]] + goods[i][1]) print(dp[-1])

确定体积的情况

如果我要求的不是尽可能最大的价值,而是刚好等于背包容量的最大价值,那么该如何去做呢?


完全背包问题

完全背包问题

描述:

有N件物品和一个容量为V的背包,每件物品都有无限个!

第i件物品的体积是vi,价值是wi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包流量,且总价值最大。

一维动态规划

完全背包问题跟01背包问题最大的区别就是每一个物品可以选无数次,因此当我们考虑到第i个物品时,我们应该考虑的情况是:不选这个物品、选一次这个物品、选两次这个物品......,直到不能再选(选的次数k,k*v[i] > j,j为当前背包容量),然后再从这些情况中选最大的。代码如下:

n, v = map(int, input().split())
goods = []
for i in range(n):
goods.append([int(i) for i in input().split()])
dp = [0 for i in range(v+1)]
for i in range(n):
for j in range(v,-1,-1): # 从后往前
k = j//goods[i][0] # 能选多少次
# 从这些次里面取最大
dp[j] = max([dp[j- x* goods[i][0]] + x * goods[i][1] for x in range(k+1)]) print(dp[-1])

一维动态规划(优化)

刚刚那个问题,我们是延续01背包的问题,从后往前递推。但是对于这个问题,其实可以通过从前往后递推。如何理解呢?

假设在考虑第i个物品时的两个状态:

A:dp[k*v[i] + x]

B:dp[(k-1)*v[i] + x]

根据前面的归纳,从前一个状态递推过来:

  • 要求A的值,应该要从k+1个状态中选出最大的:

    dp[x] + k*w[i]
    dp[v[i] + x] + (k-1)*w[i]
    dp[2*v[i] + x] + (k-2)*w[i]
    ...
    ...
    dp[(k-1)*v[i] + x] + w[i]
    dp[k*v[i] + x
  • 要求B的值,应该要从k个状态中选出最大的:

    dp[x] + (k-1)*w[i]
    dp[v[i] + x] + (k-2)*w[i]
    dp[2*v[i] + x] + (k-3)*w[i]
    ...
    ...
    dp[(k-2)*v[i] + x] + w[i]
    dp[(k-1)*v[i] + x

我们可以看到,一一对应过来的话,这两个状态实际上只差一个w[i]的值。因此:

一方面我们可以根据前一个状态(i-1)推出此时的状态,另一方面由于当前状态前面的值也是当前问题的子问题,因此我们也可以从前面的值推到后面的值。

从前往后递推的代码如下:

n, v = map(int, input().split())
goods = []
for i in range(n):
goods.append([int(i) for i in input().split()])
dp = [0 for i in range(v+1)]
for i in range(n):
for j in range(v+1):
if j >= goods[i][0]:
dp[j] = max(dp[j], dp[j-goods[i][0]] + goods[i][1]) print(dp[-1])

多重背包问题

多重背包问题

描述:

有N件物品和一个容量为V的背包。

第i件物品的体积是vi,价值是wi,数量是si。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包流量,且总价值最大。

一维动态规划

其实跟上面的完全背包问题类似,只不过我们从后往前递推的时候,物体i选取的次数应该要重新考虑下:

k = min(s[i], j//v[i]), j为当前的背包容量

代码如下:

n,v = map(int, input().split())
goods = []
for i in range(n):
goods.append([int(i) for i in input().split()]) dp = [0 for i in range(v+1)] for i in range(n):
for j in range(v, -1, -1):
# 考虑两种情况的最小值
k = min(j//goods[i][0], goods[i][2])
dp[j] = max([dp[j-x*goods[i][0]] + x*goods[i][1] for x in range(k+1)]) print(dp[-1])

一维动态规划(转换01背包)

想法很简单,直接把背包中的物品展开,展成很多数量为1的物品,这样就转换为01背包问题。代码如下:

n,v = map(int, input().split())
goods = []
for i in range(n):
goods.append([int(i) for i in input().split()]) new_goods = [] # 展开
for i in range(n):
for j in range(goods[i][2]):
new_goods.append(goods[i][0:2]) goods = new_goods
n = len(goods) # 01背包问题
dp = [0 for i in range(v+1)] for i in range(n):
for j in range(v,-1,-1):
if j>= goods[i][0]:
dp[j] = max(dp[j], dp[j - goods[i][0]] + goods[i][1]) print(dp[-1])

动态规划——背包问题python实现(01背包、完全背包、多重背包)的更多相关文章

  1. HDU 1114 完全背包 HDU 2191 多重背包

    HDU 1114 Piggy-Bank 完全背包问题. 想想我们01背包是逆序遍历是为了保证什么? 保证每件物品只有两种状态,取或者不取.那么正序遍历呢? 这不就正好满足完全背包的条件了吗 means ...

  2. hdoj2191 珍惜现在,感恩生活(01背包 || 多重背包)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2191 思路 由于每种大米可能不止一袋,所以是多重背包问题,可以直接使用解决多重背包问题的方法,也可以将 ...

  3. 01背包模板、全然背包 and 多重背包(模板)

    转载请注明出处:http://blog.csdn.net/u012860063 贴一个自觉得解说不错的链接:http://www.cppblog.com/tanky-woo/archive/2010/ ...

  4. [原]hdu2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (这个只是题目名字) (多重背包)

    本文出自:http://blog.csdn.net/svitter 原题:http://acm.hdu.edu.cn/showproblem.php?pid=2191 题意:多重背包问题.转换成为01 ...

  5. POJ 1742 Coins(多重背包, 单调队列)

    Description People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar. ...

  6. POJ 1742 (单调队列优化多重背包+混合背包)

    (点击此处查看原题) 题意分析 给你n种不同价值的硬币,价值为val[1],val[2]...val[n],每种价值的硬币有num[1],num[2]...num[n]个,问使用这n种硬币可以凑齐[1 ...

  7. POJ1276 - Cash Machine(多重背包)

    题目大意 给定一个容量为M的背包以及n种物品,每种物品有一个体积和数量,要求你用这些物品尽量的装满背包 题解 就是多重背包~~~~用二进制优化了一下,就是把每种物品的数量cnt拆成由几个数组成,1,2 ...

  8. HDU1059 二进制拆分优化多重背包

    /*问你能不能将给出的资源平分成两半,那么我们就以一半为背包,运行多重背包模版 但是注意了,由于个数过大,直接运行会超时,所以要用二进制拆分每种的个数*/ #include<stdio.h> ...

  9. DZY Loves Math II:多重背包dp+组合数

    Description Input 第一行,两个正整数 S 和 q,q 表示询问数量.接下来 q 行,每行一个正整数 n. Output 输出共 q 行,分别为每个询问的答案. Sample Inpu ...

随机推荐

  1. DL/T645-2007 及 Modbus-RTU智能电表调试工具

    最近在做微信门禁,智能电表采集,智能水表采集项目时,发现网上很多调试工具用起来不顺手,电脑里面起码下了五六个软件. 好不容易弄清楚了,就自己写一个工具,方便自己使用,也顺便造福一下其他人吧

  2. 【计算机视觉】黄金标准算法Gold Standard algorithm

    前言 最近有关于3DMM的内容,博主也只是看了个大概,并没有深入了解算法的实现原理和过程.昨天实习生问关于黄金标准算法的推导,博主也就参考一些资料熟悉了这个算法的实现过程.不太了解使用这个算法的前因后 ...

  3. 腾讯云直播+点播全线产品支持AV1,带来极致视频体验

    日前,腾讯视频云直播.点播.媒体处理全线产品均已支持AV1标准,据悉,腾讯云也是国内首家直播+点播同时支持AV1视频处理业务的公有云厂商. 据悉,AV1(Alliance for Open Media ...

  4. Slenium入门

    selenium 为浏览器测试框架,可以调用浏览器webdriver模拟浏览器操作360打开Chrome: from selenium import webdriver from selenium.w ...

  5. 防火墙阻止了虚拟机与主机之间互相ping通解决方案

    1. 打开WIN10防火墙,选择高级设置 2.入站规则 3.找到配置文件类型为“公用”的“文件和打印共享(回显请求 – ICMPv4-In)”规则,设置为允许. 如果上面步骤没有问题还ping不通,可 ...

  6. 011 SpringCloud 学习笔记7-----Zuul网关

    1.Zuul网关概述 通过前面的学习,使用Spring Cloud实现微服务的架构基本成型,大致是这样的: 我们使用Spring Cloud Netflix中的Eureka实现了服务注册中心以及服务注 ...

  7. GitBook的使用

    首先安装gitbook npm install -g gitbook-cli 检查是否安装成功 gitbook -V 然后就要建立一个文件夹进到文件夹目录下 让此文件夹初始化下 gitbook ini ...

  8. 基于DigitalOcean+LAMP+WordPress搭建个人网站

    1. 注册DigitalOcean并新建主机 为了搭建个人网站首先需要一个可以在公网范围访问的主机,可以选用国内如阿里云.国外如DigitalOcean的各种云主机提供商,这里选用DigitalOce ...

  9. 57 容器(十一)——Collections容器工具类

    Collections是一个工具类,它提供了与集合操作有关的方法,好比数组中的Arrays工具类.(jdk中的工具类名都是xxxs,有关工具类名参考:https://zhuanlan.zhihu.co ...

  10. sqlserver通过递归查找所有下级或上级部门和用户的操作实例

    --查找当前用户所在部门的所有下级包括当前部门 with cte as ( as lvl from Department union all from cte c inner join Departm ...