01背包问题——大背包:

题目描述:

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

限制条件:

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

解析:

一般的01背包:

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

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

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

全新的动态规划:

  • dp数组含义 d p [ i ] [ j ] dp[i][j] dp[i][j]=从前 i i i个物品中选择出价值为 j j j的物品的最小体积(若前 i i i个物品堆不出价值 j j j,则最小体积为 i n f inf 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 dp[0][0]=0;dp[0][1i=1nvi]=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]\} dp[i][j]=min{dp[i1][j],dp[i1][jv[i]]+w[i]}
  • 递推方向:从上到下,即只要知道第 i i i行就能求出第 i + 1 i+1 i+1行。
  • 结果:为 d p dp dp中第 n n n行中小于等于 W W W的元素的最大列号,即 m a x ⁡ { j ∣ d p [ n ] [ j ] ≤ W } max⁡\{j|dp[n][j]≤W\} max{jdp[n][j]W}

代码:

#include 
#include 
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;
}

你可能感兴趣的:(ACM)