OpenJ_Bailian 2755 神奇的口袋

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Qin7_Victory/article/details/80263485

题目:

        有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40。John现在有n个想要得到的物品,每个物品的体积分别是a 1,a 2……a n。John可以从这些物品中选择一些,如果选出的物体的总体积是40,那么利用这个神奇的口袋,John就可以得到这些物品。现在的问题是,John有多少种不同的选择物品的方式。


Input 输入的第一行是正整数n (1 <= n <= 20),表示不同的物品的数目。接下来的n行,每行有一个1到40之间的正整数,分别给出a 1,a 2……a n的值。 Output 输出不同的选择物品的方式的数目。
Sample Input

3
20
20
20

Sample Output

3

  思路:
        这道题要求的是给出n个物品的重量,要求让他们的重量和为40时,有多少种情况。       
        刚开始看这道题的时候,觉得用搜索就可以写,从重量为40,物品数为n开始往下找。两种情况,一种是选择这个物品,重量减去a[i], 一种是不选择这个物品,重量不变,继续往下找。
        

int dfs(int sum,int num)
{
    if(sum == 0)
        return 1;
    if(num == 0)
        return 0;
    return dfs(sum-a[num],num-1)+dfs(sum,num-1);            //取或者不取
}

    当然,如果会用dp写也是挺不错的。对于dp大家对于01背包这个还算了解吧,其实这个和它也差不多。在解决dp问题的时候,我们应该从后往前推,找到问题的来源,比如在这道题中,要求的是重量为40时,有多少种情况,那么我们可以利用二维数组dp[i][j], i表示的是重量,j表示物品的个数。 当然dp[i][j]的数值应该等于重量为i,数值为j-1的情况相同。 如果a[j]恰好和重量i相等,那么dp[i][j]就加1,如果a[j]小于i时,那么dp[i][j] += dp[i-a[j]][j-1]。其实这个等式表示的是重量为i,数量为j的情况个数,应该等于其本身的情况再加上重量为 i-a[j],物品个数为j-1的 情况。
        

for(int i = 1; i <= 40; i++)    //表示物品的总重量
{
    for(int j = 1; j <= n; j++) //表示前j种物品在重量为i时,有几种情况
     {
          dp[i][j] = dp[i][j-1];  //重量为i, 前j-1个物品的情况个数
          if(i == a[j])
              dp[i][j]++;         //情况加1
           if(i > a[j])
              dp[i][j] += dp[i-a[j]][j-1];  //现在的情况数加上  重量为i-a[j]时,j-1个物品的情况数
     }
}

       我们也可以用一维数组来表示重量,其意义和上面一样。代码如下

for(int i = 1; i <= n; i++)
        {
            for(int j = 40; j >= 1; j--)
            {
                if(dp[j] && j+a[i] <= 40)
                {
                    dp[j+a[i]] += dp[j];              
                }
            }
            dp[a[i]]++;
        }

        



        

猜你喜欢

转载自blog.csdn.net/Qin7_Victory/article/details/80263485