算法学习Day2之背包算法2
算法学习Day2之背包算法2
一、引言:每天一个不可能了,哭。没时间。这次主题记录一下完全背包算法,先继续0-1背包优化,再完全背包,和其优化。
首先列一下主要参考资料:转载:
(1)百度百科:https://baike.baidu.com/item/%E8%83%8C%E5%8C%85%E9%97%AE%E9%A2%98/2416931?fr=aladdin
(2)https://www.cnblogs.com/yun-an/p/11037618.html
(3)https://segmentfault.com/a/1190000012829866
(4)https://blog.csdn.net/liusuangeng/article/details/38374405
二、0-1背包算法的优化
首先0-1基础的状态转移方程为:
- j<w,dp[i][j] = dp[i-1][j] //背包装不下该物品,最大价值不变
- j>=w, dp[i][j] = max{ dp[i-1][j-list[i].w] + v, dp[i-1][j] } //和不放入该物品时同样达到该体积的最大价值比较
三、优化方法:
观察状态转移方程的特点,我们发现dp[i][j]的转移只与dp[i-1][j-list[i].w]和dp[i-1][j]有关,即仅与二维数组本行的上一行有关。因此,我们可以将二维数组优化为一维数组。不过这里要注意两点:1.j<w的状态转移方程不再需要了。2.为保证每个物品只能使用一次,我们倒序遍历所有j的值,这样在更新dp[j]的时候,dp[j-list[i].w]的值尚未被修改,就不会出现一个物品重复使用的问题。这是(2)的 描述。我看完优点不懂,为啥仅与二维数组本行的上一行有关就可以优化为一维数组。
继续查找资料。详见(4),方法为:滚动数组。我的理解,因为现在存储的值i的意义为存储每个之前的状态,但是当前并不需要存储之前所有的。只要存储前一个的,然后用现在去代替它。
一维优化后的状态转移方程为:
dp[j] = max{ dp[j-list[i].w] + v, dp[j] }
四、示例代码,还是贴一下:
#include<cstdio> #include <iostream> #include <algorithm> using namespace std; struct Thing { int w; int v; }list[101]; int f[1001]; int main() { int s, n;//背包容量和物品总数 while (cin >> s >> n) { for (int i = 1; i <= n; i++) { cin >> list[i].w >> list[i].v; } for (int i = 0; i <= s; i++) f[i] = 0;//初始化二维数组 for (int i = 1; i <= n; i++)//循环每个物品,执行状态转移方程 { for (int j = s; j >= list[i].w; j--) { f[j] = max(f[j], f[j - list[i].w] + list[i].v); } } printf("%d\n", f[s]); } return 0; }
五、完全背包算法问题描述:有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是c,价值是w。将哪些物品装入背包可使这些物品的体积总和不超过背包容量,且价值总和最大。(百度百科)我的理解:
六、问题解决思路:
这个问题非常类似于01背包问题,所不同的是每种物品有无限件。也就是从每种物品的角度考虑,与它相关的策略已并非取或不取两种,而是有取0件、取1件、取2件……等很多种。(基本状态转移方程的思路都一样),但是百度百科的基本状态转移方程,看的我莫名奇妙,推荐看(3)的2.2.挺易懂的。
我的理解:与0-1背包相比,多了一层对于每个物品放几次达到最优的问题,所以其状态转移方程区别在于选择放物品时,加个变量为放多少个和对应加多少个价值。
七、完全背包的基本状态转移方程:
- j<w,dp[i][j] = dp[i-1][j] //背包装不下该物品,最大价值不变
- j>=w, dp[i][j] = max{ dp[i-1][j-k*list[i].w] + k*v, dp[i-1][j] } //和不放入该物品时同样达到该体积的最大价值比较
由状态转移方程变为dp算法,我会了。就不想写了。
八、完全背包优化:O(nW)优化
我的理解:对于某个物品i,还是使用最初的动态规划方法来进行分析。
对于0-1背包是在选择放时,使用前一个状态的中得到j-w的体积下的最优解。
而完全背包为:选择放时,因为可以继续放当前物品i,所以寻找的是在有当前物品的状态下得到j-w的体积下的最优解。
所以完全背包的状态转移方程为:
- j<w,dp[i][j] = dp[i-1][j] //背包装不下该物品,最大价值不变
- j>=w, dp[i][j] = max{ dp[i][j-list[i].w] + v, dp[i-1][j] } //和不放入该物品时同样达到该体积的最大价值比较
所以0-1背包的状态转移方程为:
- j<w,dp[i][j] = dp[i-1][j] //背包装不下该物品,最大价值不变
- j>=w, dp[i][j] = max{ dp[i-1][j-list[i].w] + v, dp[i-1][j] } //和不放入该物品时同样达到该体积的最大价值比较
将这两个都列出来,好对比。
继续优化:二维改一维
思路和本文开头一样,所以就不写优化步骤了。
状态转移方程为:
dp[j] = max{ dp[j-list[i].w] + v, dp[j] }
好了,因为时间问题。代码就不想贴了。最重要的是状态转移方程的得到,和状态转移方程用dp方法实现。