算法学习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方法实现。

 

posted on 2020-09-04 22:23  一次性炮灰  阅读(205)  评论(0编辑  收藏  举报

导航