问题描述:

给出N个物品,每个物品的体积为w[i],这些物品可以使多大的背包完全装满?

 

分析:

用dp[v]表示容量为i的背包可以被装满。 0 <= v  <= sum(w[i])

在循环开始前,初始化dp[0] = true,dp[i] = false (i>0)。

第一次循环,表示只有一件物品可选,那么下标为w[0]的背包被置为true。

第二次循环,表示前两件物品可选。那么在所有置为true的下标基础上,加上一个w[1],依然为true。

dp[ j ] == true   =>  dp[ j + w[i] ] = true

但是如果求解时,j从小到大求的话,就会出现问题。

比如 j = 0时, dp[ w[0] ]被置为true。j不断增大,当j = w[0]时,dp[ w[0] + w[0] ]也被置为true。

实际上,物品0只有一件,这样的情况是取不到的。

怎样避免?自然是用逆序求值了。

dp[ j ] = true    仅当  dp[ j - w[i] ] == true。

上代码:

int main()
{
    int a[6] = { 8,3,12,7,9,7 };
    int n = 6;
    int i,j,sum = 46;
    int dp[47] = {0};

    dp[0] = 1;
    for(i = 0;i < n; i++)
    {
        for(j=sum;j>=a[i];j--)
        {
            dp[j] |= dp[ j - a[i] ];
        }
    }

    return 0;
}

分析一下循环过程,对于理解用一维数组解背包问题的思维方式非常有帮助。

循环开始前,初始化dp[0] = 1,其他都是0。

      

第一次循环结束后,下标为a[0]的dp被置为1。

第二次循环后,所有true的下标加上a[1]都变成true。

此后的每次循环,都是在所有合法和的基础上,加上一个a[i]。

         

 

最终:

- dp 0x0100fa0c int [47]
[0] 1 int
[1] 0 int
[2] 0 int
[3] 1 int
[4] 0 int
[5] 0 int
[6] 0 int
[7] 1 int
[8] 1 int
[9] 1 int
[10] 1 int
[11] 1 int
[12] 1 int
[13] 0 int
[14] 1 int
[15] 1 int
[16] 1 int
[17] 1 int
[18] 1 int
[19] 1 int
[20] 1 int
[21] 1 int
[22] 1 int
[23] 1 int
[24] 1 int
[25] 1 int
[26] 1 int
[27] 1 int
[28] 1 int
[29] 1 int
[30] 1 int
[31] 1 int
[32] 1 int
[33] 0 int
[34] 1 int
[35] 1 int
[36] 1 int
[37] 1 int
[38] 1 int
[39] 1 int
[40] 0 int
[41] 0 int
[42] 0 int
[43] 0 int
[44] 0 int
[45] 0 int
[46] 0 int

 

posted on 2017-11-22 17:22  newbird2017  阅读(216)  评论(0编辑  收藏  举报