01背包
这两天的upc被虐的很惨,动态规划,搜索都没接触过,现在学数据结构,没办法了,双管齐下吧,Orz!
01背包:
有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。
第 ii 件物品的体积是 vivi,价值是 wiwi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,VN,V,用空格隔开,分别表示物品数量和背包容积。
接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤10000<N,V≤1000
0<vi,wi≤10000<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
8
01背包
(划分依据:依据最后一步的不同来)
令f[i][j]是前i个物品,容量不超过j的最大价值
最后一步也就是看看第i个物品的决策:
不选:那第i个物品及其之前的价值相同,所以f[i-1][j]
选:这里只包含了选,所以第i个物品及其之前的价值=f[i-1][j-vi]+w
*********************************我来debug,下面的说法有点问题QAQ,可以看上面的
01背包问题是最基础的动态规划
这个题属于有限集合求最大值的类型,一共有2^n的情况,可以采用闫式分析法
集合:所有只考虑前i个物品,且总体积不超过j的选出的集合
属性:集合中每一个方案的最大价值
确定状态转移方程一定要多做题!!
二维f[i][j]中i表示前i个物品,而j一般代表着限制条件,比如容量、重量等等
01分别代表着选与不选,二维01问题f[i][j]代表着前i个物品,背包容量j的情况下的最优解(记住是最优解),所以每一次i的增长,会随着价值和体积的变化最优解而不断变化
这个就很灵活,比起之前做的题方法死板板的,跳跃式的基本无缘的情况下,这种很方便了
当前的状态要依赖于上一个状态,上一个状态又要依赖于再上一个状态...有点点像递推啊有木有有木有
所以要定一个初始状态f[0][0]=0,前0个体积为0的情况下价值自然就是0啦
好,下面开始上重中之重,也就是核心部分:
刚刚都说了01背包中01代表着选与不选的问题,这下自然分两类:
①背包容量不够(此时的j<v[i])
这个情况下自然不选,这个不选的最优解其实就等于上一个物品的最优解(因为压根没选上啊,没进背包何谈更新最优解)
f[i][j]=f[i-1][j];
②背包容量足够的情况下,这个就看自主分配了
(1)不选,同理容量不够,大同小异:
f[i][j]=f[i-1][j];
(2)选:
刚刚说了此时的状态依赖于上一个状态
f[i][j]=f[i-1][j-v[i]]+w[i](上一个状态也就是前i-1个物品体积自然就是j-v[i](已经选上第i个了嘛),两边要等价,再加上选上的这个第i个物品的价值w[i])
然后判断一下最优解的情况,也就是求其最大值:
#include<iostream> using namespace std; int f[1010][1010],v[1010],w[1010]; int main(){ int n,m; cin>>n>>m; for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; f[0][0]=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(j<v[i])//装不下 f[i][j]=f[i-1][j]; else//装得下 f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]); } } cout<<f[n][m]<<endl; return 0; }
二维的f[i][j]本质上是可以求得任意合法的i与j的最优解
可是题目里只让求n个物品的最优解,那之前求的那些i不是浪费了么
所以此代码可以优化到一维,二维表示也就是f[n][j]
状态f[j]定义:N件物品背包容量j下的最优解
但为什么是逆序,
*************************************************************************************************************************************************
(3)为什么一维情况下枚举背包容量需要逆序?在二维情况下,状态f[i][j]是由上一轮i - 1的状态得来的,f[i][j]与f[i - 1][j]是独立的。而优化到一维后,如果我们还是正序,则有f[较小体积]更新到f[较大体积],则有可能本应该用第i-1轮的状态却用的是第i轮的状态。
(4)例如,一维状态第i轮对体积为 33 的物品进行决策,则f[7]由f[4]更新而来,这里的f[4]正确应该是f[i - 1][4],但从小到大枚举j这里的f[4]在第i轮计算却变成了f[i][4]。当逆序枚举背包容量j时,我们求f[7]同样由f[4]更新,但由于是逆序,这里的f[4]还没有在第i轮计算,所以此时实际计算的f[4]仍然是f[i - 1][4]。
(5)简单来说,一维情况正序更新状态f[j]需要用到前面计算的状态已经被「污染」,逆序则不会有这样的问题。
作者:深蓝
链接:https://www.acwing.com/solution/content/1374/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
****************************************************************************************************************************************************
上面这是一位大佬写的,我自己懂的不是很彻底,就就直接复制粘贴过来了,留着自己思考QAQ
啊,二刷明白了,一维的优化其实是在二维的基础上进行优化,两个式子等价:
所以需要逆序就是从大到小循环f[j-v[i]]还没有更新过,这里面存的值就是上一层的值也就是二维的f[i-1][j-v[i]+w[i]]两个式子等价
for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(j<v[i]) f[i][j]=f[i-1][j];//优化前 if(j<v[i]) f[j]=f[j]//优化后,0没有选上,背包容量没有任何的变化,也就是最优解没有啥变化 //当然此步骤可以省略 else f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);//优化前 f[j]=max(f[j],f[j-v[i]]+w[i]); //优化后 } }
综上再进行一步优化:只有当枚举的背包容量 >= v[i] 时才会更新状态
for(int i=1;i<=n;i++) { for(j=m;j>=v[i];j--) { f[j]=max(f[j],f[j-v[i]]+w[i]); } }
*********************************************************************************
关于状态f[j]的补充说明
二维下的状态定义f[i][j]是前 ii 件物品,背包容量 jj 下的最大价值。一维下,少了前 ii 件物品这个维度,我们的代码中决策到第 ii 件物品(循环到第i轮),f[j]就是前i轮已经决策的物品且背包容量 jj 下的最大价值。
因此当执行完循环结构后,由于已经决策了所有物品,f[j]就是所有物品背包容量 jj 下的最大价值。即一维f[j]等价于二维f[n][j]。
同样复制刚刚那位大佬的
#include<iostream> using namespace std; int f[1010],v[1010],w[1010]; int main(){ int n,m; cin>>n>>m; for(int i=1;i<=n;i++) cin>>v[i]>>w[i]; 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]); } } cout<<f[m]<<endl; return 0; }
最然最后优化的版本,连同输入一起进行
#include<iostream> using namespace std; int f[1010],v,w; int main(){ int n,m; cin>>n>>m; for(int i=1;i<=n;i++) { cin>>v>>w; for(int j=m;j>=v;j--) f[j]=max(f[j],f[j-v]+w); } cout<<f[m]<<endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具