0/1背包

0/1背包的问题模型如下:

  给定N个物品,其中第i个物品的体积为V,价值为Wi 。有一容积为M的背包,要选择一些物品放入背包,使物品体积不超过M的前提下,物品的价值总和最大。

dp[i][j]表示从前i个物品中选出了总体积为j的物品放入背包,物品的最大价值。即我们很容易得出解决的代码:

memset(dp,0,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++)
            dp[i][j]=dp[i-1][j];
        for(int j=v[i];j<=m;j++)
            dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
    }

根据上面的代码 我们可以看出 状态方程的推导只和当前状态以及上一状态有关。所以我们可以用滚动数组优化

memset(dp,0,sizeof(dp));
    dp[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++)
            dp[i&1][j]=dp[(i-1)&1][j];
        for(int j=v[i];j<=m;j++)
            dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j-v[i]]+w[i]);
    }

这里我们只要2*m的空间即可

其实进一步分析代码,在每个阶段的开始,我们实际上只是执行了一次从dp[i-1][]到dp[i][]的一次拷贝,也就是说我们可以进一步省略掉dp数组的第一维

即dp[j]表示背包中放入总体积为j的最大价值

memset(dp,0,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=m;j>=v[i];j--)
            dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    }

我们应该可以注意到,我们的第二重循环采用了倒序的方式,这是为了满足0/1背包问题中每个物品是唯一的,只能放入一次的要求

 

 

 

posted @ 2019-02-16 14:45  WAKBGAN  阅读(194)  评论(0编辑  收藏  举报