01背包问题——大背包:

题目描述:

  • 有n个物品,每个物品有两个属性:一个是体积 w i w_i ,一个是价值 v 1 v_1 ,可以表示为: { ( w 1 , v 1 ) , ( w 1 , v 1 ) , , ( w 1 , v n ) } \{(w_1,v_1 ),(w_1,v_1 ),…,(w_1,v_n )\} 。同时我们还有一背包,背包的容量用W表示。现在我们将物品放入背包,放入的物品体积的总和不得超过背包的体积。问这个背包能装下的最大价值。

限制条件:

  • 1 n 100 1≤n≤100
  • 1 W 1 0 9 1≤W≤10^9
  • 1 w i 1 0 7 1≤w_i≤10^7
  • 1 v i 100 1≤v_i≤100

解析:

一般的01背包:

  • 先前写过一篇一般的01背包问题 的博客链接如下:https://blog.csdn.net/ACM_hades/article/details/89034229
  • 题目描述是一样的,只是修改了限制条件,这篇博客考虑的是一个超大的背包。如果使用上一篇的动态规划,其实时间复杂度为 O ( n W ) = 1 0 11 O(nW)=10^{11} ,这个时间复杂度就很高了。主要问题出在背包容量 W W 太大。

  • 上一篇博客的 d p [ i ] [ j ] dp[i][j] :表示将第 i i 到第 n n 个物品装入容量为 j j 的背包中能得到的最大价值。也就是我们限制背包容量求最大价值,同时动态规划的时间复杂度也 i i j j 的含义而确定。
  • 其实我们发现: d p [ i ] [ j ] dp[i][j] 的含义主要由三部分确定:
    • i i 的含义
    • j j 的含义,
    • d p dp 数组中存的值的含义。
    • 并且 i i j j 的取值范围决定了算法的时间复杂度。
  • 例如在上一篇博客中: i i =物体索引(0-n), j j =背包容量(0-W), d p dp =最大价值

  • 为了降低时间复杂度我们必须要改变dp数组含义为。由于时间复杂度主要由 i i j j 的含义决定,所以我们必须将 i i j j 的含义于取值返回比较小的 n n v v 数组 联系起来,将较大的 W W d p dp 数组中存的值联系起来。这样我们得到这样的 d p dp 数组: d p [ i ] [ j ] dp[i][j] =从前 i i 个物品中选择出价值为 j j 的物品的最小体积(若前 i i 个物品堆不出价值 j j ,则最小体积为 i n f inf )

全新的动态规划:

  • dp数组含义 d p [ i ] [ j ] dp[i][j] =从前 i i 个物品中选择出价值为 j j 的物品的最小体积(若前 i i 个物品堆不出价值 j j ,则最小体积为 i n f inf )
  • 初始条件 d p [ 0 ] [ 0 ] = 0 ; d p [ 0 ] [ 1 i = 1 n v i ] = i n f dp[0][0]=0;dp[0][1-∑_{i=1}^nv_i ]=inf
  • 递推公式 d p [ i ] [ j ] = m i n { d p [ i 1 ] [ j ] , d p [ i 1 ] [ j v [ i ] ] + w [ i ] } dp[i][j]=min⁡\{dp[i-1][j],dp[i-1][j-v[i]]+w[i]\}
  • 递推方向:从上到下,即只要知道第 i i 行就能求出第 i + 1 i+1 行。
  • 结果:为 d p dp 中第 n n 行中小于等于 W W 的元素的最大列号,即 m a x { j d p [ n ] [ j ] W } max⁡\{j|dp[n][j]≤W\}

代码:

#include <iostream>
#include <string.h>
using namespace std;
#define Max_n 105
#define Max_v 105
#define Inf 1000000005

int n,W;
int w[Max_n],v[Max_n];
int dp[Max_n][Max_n*Max_v+1]; //记录状态的数组

void Dynamic_degradation(){
    //初始化dp
    fill(dp[0],dp[0]+Max_n*Max_v,Inf);
    dp[0][0]=0;

    for(int i=1;i<=n;i++){
        for(int j=0;j<=Max_n*Max_v;j++){
            dp[i][j]=dp[i-1][j];
            if(j>=w[i])
                dp[i][j]=min(dp[i][j],dp[i-1][j-v[i]]+w[i]);
        }
    }

    int result=0;
    for(int i=0;i<=Max_n*Max_v&dp[n][i]<=W;i++)
        if(i>result)
            result=i;
    cout<<result<<endl;
}

猜你喜欢

转载自blog.csdn.net/ACM_hades/article/details/89213283