关于背包问题的相关思考
前述
这里写一点我对最近写到的背包算法的想法,觉得比较巧妙所有就准备写在博客里
这里推荐几个比较好的博客和视频,学到了很多东西
CSDN
BiliBili
基础0-1背包
问题描述
对于一堆物体,每个物体就只有一个,每个物体有它的体积与价值,问一个体积有限的背包怎么能够拿到价值最高的物体
问题分析
其实本质上还是动态规划问题,我们假设有一个二维数组dp[i][j]
,其中的i
对应在只考虑前i个物体的情况,其中的j
可以抽象理解成考虑前j个背包每个单位体积,那么对应的值就是在只考虑前i个物体,考虑前j个背包的体积的最大价值。这么一说,那么这个问题就简单了,只需要每次更新要不要加入这个物体就好了。这么说肯定很抽象,那么我们来举个例子。
假如有一堆物体,将它们放到一个容量为10的背包中,物体的相关属性如下:
物品编号 | 体积 | 价值 |
---|---|---|
0 | 2 | 3 |
1 | 3 | 4 |
2 | 4 | 4 |
3 | 6 | 6 |
那么就会有这么一个算法过程:
i\j | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 | 3 |
1 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 | 7 | 7 |
2 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 | 11 | 11 |
3 | 0 | 0 | 3 | 4 | 4 | 7 | 7 | 7 | 7 | 11 | 11 |
核心代码
1 | for(int i=1;i<m;i++) |
代码优化
可以看出这个代码的空间复杂度是O(i+j),但是我们观察可以看到,每次循环我们只会用到上一层的价值行,所有可以在这个步骤上下功夫缩减成一维数组。直接放出结果:
1 | for(int i=0;i<m;i++) |
这里可以看到内置循环是从右往左,这个顺序不能改变,因为如果改变就会直接改变后面的结果,导致之前的数据丢失,所以不能改变。
完全背包
问题描述
对于一堆物体,每个物体有无数个,每个物体有它的体积与价值,问一个体积有限的背包怎么能够拿到价值最高的物体。
问题分析
其实就是0-1背包变得可以覆写数据了,根据上面优化之后的代码,我们可以直接变成正向循环,让他变得可以直接覆写,这样就实现了动态改变放入的物品数量。当然也可以从二维数组开始写,因为我们不知道到底放入几个相同物体,那么就需要再加一层循环。这里我也贴出了代码,但是建议直接去看优化后的代码。
核心代码
1 | for (int i = 1; i <= n; i ++ ){ |
代码优化
1 | for(int i=0;i<m;i++) |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Juanxcg' Blog!