动态规划——背包问题python实现(01背包、完全背包、多重背包)

目录

  • 01背包问题
  • 完全背包问题
  • 多重背包问题

参考:

背包九讲——哔哩哔哩

背包九讲


01背包问题

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])

原文地址:https://www.cnblogs.com/anzhengyu/p/11408466.html

时间: 2024-10-12 18:05:59

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

01、完全、多重背包模板

背包问题: 背包总容量为W,有n件重量为weight[i],权值为value[i]的物品 1.01背包: 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放. 1 void ZeroOnePack (int weight,int value) 2 { 3 for (int w = W; w >= weight; w--) 4 dp[w] = max(dp[w - weight] + value, dp[w]); 5 } 2.完全背包: 每件物品有无限多个. void Complet

背包问题专栏(01,完全,多重)

本题的模板是套用了 A.S.KirigiriKyouko 的模板.请dalao见谅 一.01背包 有N件物品和一个容量为V的背包.第i件物品的价格(即体积,下同)是w[i],价值是c[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 这是最基础的背包问题,总的来说就是:选还是不选,这是个问题<( ̄ˇ ̄)/ 相当于用f[i][j]表示前i个背包装入容量为v的背包中所可以获得的最大价值. 对于一个物品,只有两种情况 情况一: 第i件不放进去,这时所得价值为:f[i-

【CJWYH】RHL的背包题解(多重背包)

题面 [问题描述] CJ中学组织学生出去春游,作为学神的RHL自然不会放过这一大好时机,他有n种物品,第i件物品有c[i]个,每个体积为v[i],价值为w[i],RHL现在有一个体积为V的背包,他想让他带的东西价值之和最大,且体积之和不超过V,你能帮帮他吗?注意物体不能分割. [输入] 输入文件名为bag.in,分为若干行.第一行包含两个正整数n,V. 第二行到第n+1行分别描述第i种物品的数量c[i],体积v[i],价值w[i] [输出] 输出文件名为bag.out,一行输出一个整数,表示最大

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

转载请注明出处:http://blog.csdn.net/u012860063 贴一个自觉得解说不错的链接:http://www.cppblog.com/tanky-woo/archive/2010/07/31/121803.html 模版就直接贴代码: 01背包模板: /* 01背包问题 01背包问题的特点是,">每种物品仅有一件.能够选择放或不放. 01背包问题描写叙述: 有N件物品和一个容量为V的背包. 第i件物品的重量是c[i],价值是w[i]. 求解将哪些物品装入背包可使这些物品

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

本文出自:http://blog.csdn.net/svitter 原题:http://acm.hdu.edu.cn/showproblem.php?pid=2191 题意:多重背包问题.转换成为01背包解.多重背包转化为01背包的关键在于把件数从整体中孤立出来作为一个新的个体,也就是说不管分类,有多少件就有多少种. AC代码: //============================================================================ // Na

动态规划——背包问题入门

动态规划--背包问题入门 1. 01背包 概述 给出N个物品,每个物体都具有一定的体积和价值,而每个物体都只有一个. 拥有一个V体积的背包,问应如何装包才能使背包中物体的总价值最大? 解题思路 背包问题是典型的动态规划类题目,而动态规划是典型的通过规律找出正解的方法.所以解题思路的关键在于如何寻找不同数据之间的关系(状态转移). 直接描述不方便解释,我们以例题为例: (注:01背包问题不涉及因为物体的形状.大小等而如何放入背包的问题,只是单纯考虑体积和价值.我们可以理解成每个物体都是液体,而这个

【POJ1882】Stamps,灵活多重背包,详细题意!!!(题解也有)

我之所以发题解(题意),就是因为百度搜索上发的太少了,而且还不清晰,所以: 题意:我直接拿数据说话吧(可以直接看下面的大号粗体字,如果你语文够好的话.) 5 2 4 1 4 12 21 4 1 5 12 28 10 2 5 1 7 16 31 88 5 1 15 52 67 99 6 2 3 1 5 8 4 1 5 7 8 0 第一行 5 是最多能拿5张邮票,第二行2是有两组邮票. 第三行4是该组有4张邮票,然后4个数是4个面额. 第五行"10"开始就是下一组数据了,输入到"

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

Description Input 第一行,两个正整数 S 和 q,q 表示询问数量.接下来 q 行,每行一个正整数 n. Output 输出共 q 行,分别为每个询问的答案. Sample Input 30 3 9 29 1000000000000000000 Sample Output 0 9 450000036 Hint 感谢the Loser协助更正数据对于100%的数据,2<=S<=2e6??,1<=n<=101810^{18}10?18??,1<=q<=10

【动态规划】背包问题(一) 01背包 完全背包 多重背包

一.01背包 有N件物品和一个容量为V的背包.第i件物品的价格(即体积,下同)是w[i],价值是c[i].求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大. 这是最基础的背包问题,总的来说就是:选还是不选,这是个问题<( ̄ˇ ̄)/ 相当于用f[i][j]表示前i个背包装入容量为v的背包中所可以获得的最大价值. 对于一个物品,只有两种情况 情况一: 第i件不放进去,这时所得价值为:f[i-1][v] 情况二: 第i件放进去,这时所得价值为:f[i-1][v-c[i]]+w