
动态规划—背包问题
背包问题(Knapsack problem)是一种组合优化的NP完全(NP-Complete,NPC)问题。问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。本章所有的背包问题讨论均使用 集合的思想求解背包问题。一般来讲,背包问题有以下几种分类:
发布日期:2021-05-08 11:10:52
浏览次数:18
分类:精选文章
本文共 2216 字,大约阅读时间需要 7 分钟。
背包问题
1.01背包
2.完全背包 3.多重背包 4.分组背包01背包问题
一般01背包问题
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。输出最大价值。
用状态表示和状态计算解决背包问题:
状态表示:f[i][j]表示使用前i个物品,体积不超过j的最大价值
状态转移:状态转移从最后一个物品分析,考虑不重不漏的情况: 1.分为使用第i个物品; 2.不使用第i个物品。
则
f [ i ] [ j ] = m a x { f [ i − 1 ] [ j ] ; 不 选 第 i 个 物 品 f [ i − 1 ] [ j − v i ] + w i ; 选 第 i 个 物 品 f[i][j] =max\begin{cases} f[i - 1][j];不选第i个物品\\ f[i - 1][j - v_i] + w_i;选第i个物品\\\end{cases} f[i][j]=max{ f[i−1][j];不选第i个物品f[i−1][j−vi]+wi;选第i个物品 不选第i
个物品则体积仍为j
,即直接从f[i - 1][j]
转移,若选择第i
个物品,则体积需要减去i
个物品对应的vi
,加上对应的价值wi
。 //二维空间for(int i = 1; i <= n; i++) for(int j = 0; j <= m; j++)//m表示可容纳的最大体积 if(v[i] > j) f[i][j] = f[i - 1][j]; else f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]);//v[i] <= j
从转移状态方程来看第i
层的状态方程都是从i-1
层转移过来的,可以从空间上优化一下。去掉第一维,但是要保证第i
层的f
是使用第i-1
层的f
来更新,若单纯去掉第一维:
//!!!错误代码for(int i = 1; i <= n; i++) for(int j = 0; j <= m; j++)//m表示可容纳的最大体积 if(v[i] > j) f[j] = f[j]; else f[j] = max(f[j], f[j - v[i]] + w[i]);//v[i] <= j
在上述代码第i
层时,较大的j
是用更小的j
来更新的,但是f[j]
是从小到大来维护,因此上次代码虽然省略了第一维,但是第i层的f[j]的更新是利用第i层的f[j - v[i]]
来更新的,应该使用第i-1层
的!为了避免这个问题,可以将上述第二层循环从大到小来枚举即可解决这个问题:
for(int i = 1; i <= n; i++) for(int j = m; j >= v[i]; j--)//从大到小来枚举 f[j] = max(f[j], f[j - v[i]] + w[i]);//v[i] <= j
从大到小枚举的时候,更新f[j]
时使用的f[j - v[i]]
在第i
层还未更新,则使用的f[j - v[i]]
是上一层即i-1
的状态。
二维费用01背包问题
有 N 件物品和一个容量是 V 承重是 M 的背包。每件物品只能使用一次。第 i 件物品的体积是 vi,重量是 mi,价值是 wi。求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,总质量不超过背包承重,且总价值最大。输出最大价值。
用状态表示和状态计算解决背包问题:
状态表示:f[i][j][k]表示使用前i个物品,体积不超过j,重量不超过k的最大价值
状态转移:状态转移从最后一个物品分析,考虑不重不漏的情况: 1.分为使用第i个物品; 2.不使用第i个物品。
则
f [ i ] [ j ] [ k ] = m a x { f [ i − 1 ] [ j ] [ k ] ; 不 选 第 i 个 物 品 f [ i − 1 ] [ j − v i ] [ k − m i ] + w i ; 选 第 i 个 物 品 f[i][j][k] =max\begin{cases} f[i - 1][j][k];不选第i个物品\\ f[i - 1][j - v_i][k-m_i] + w_i;选第i个物品\\\end{cases} f[i][j][k]=max{ f[i−1][j][k];不选第i个物品f[i−1][j−vi][k−mi]+wi;选第i个物品 则实际代码可以使用两维空间,但是两个限制都要从大到小枚举:for(int i = 1; i <= n; i++) for(int j = V; j >= v1[i]; j--)//从大到小来枚举 for(int k = M; k >= v2[i]; k--) f[j][k] = max(f[j][k], f[j - v1[i]][k - v2[i]] + w[i]);
发表评论
最新留言
关注你微信了!
[***.104.42.241]2025年04月15日 07时33分33秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
(九)实现页面底部购物车的样式
2021-05-08
python-day3 for语句完整使用
2021-05-08
基于LabVIEW的入门指南
2021-05-08
weblogic之cve-2015-4852
2021-05-08
Java注释
2021-05-08
C++ 函数重载
2021-05-08
使用mybatis-generator生成底层
2021-05-08
Mybatis【5】-- Mybatis多种增删改查那些你会了么?
2021-05-08
计算输入的一句英文语句中单词数
2021-05-08
lvs+keepalive构建高可用集群
2021-05-08
6 个 Linux 运维典型问题
2021-05-08
取消vim打开文件全是黄色方法
2021-05-08
一个系统部署多个tomcat实例
2021-05-08
HP服务器设置iLO
2021-05-08
从头实现一个WPF条形图
2021-05-08
使用QT实现一个简单的登陆对话框(纯代码实现C++)
2021-05-08
QT :warning LNK4042: 对象被多次指定;已忽略多余的指定
2021-05-08
GLFW 源码 下载-编译-使用/GLAD配置
2021-05-08
针对单个网站的渗透思路
2021-05-08