OpenJ_Bailian 2755 神奇的口袋(dp+dfs)

題目:

        有一個神奇的口袋,總的容積是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]]++;
        }

        



        

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章