描述
有乙個神奇的口袋,總的容積是40,用這個口袋可以變出一些物品,這些物品的總體積必須是40。john現在有n個想要得到的物品,每個物品的體積分別是a1,a2……an。john可以從這些物品中選擇一些,如果選出的物體的總體積是40,那麼利用這個神奇的口袋,john就可以得到這些物品。現在的問題是,john有多少種不同的選擇物品的方式。
輸入
輸入的第一行是正整數n (1 <= n <= 20),表示不同的物品的數目。接下來的n行,每行有乙個1到40之間的正整數,分別給出a1,a2……an的值。
輸出
輸出不同的選擇物品的方式的數目。
樣例輸入320
2020
樣例輸出
3思路:思路有兩種,一種是遞迴的方法;另一種是動態規劃dp。
①對於遞迴方法:對於挑選某個物品,都有2種選擇:選擇當前物品後再取看下乙個物品或者是不選當前這個物品直接去看下乙個物品,故方法數為這兩種情況和。此處的遞迴是從後向前進行的(先訪問j再去訪問j-1)。因此對於第j個物品,它的體積為v[j],如果不挑選的話則容量剩為i,因此在前j個物品中,不挑選j物品而總體積達到i的方法總數為way(i,j-1);如果挑選的話則容量剩為i-v[j],因此此時在前j個物品中,挑選j物品總體積達到i的方法總數為way(i-v[j],j-1)。因此在前j個物品中,讓物品總體積達到i的方法總數為way(i,j)=way(i,j-1)+way(i-v[j],j-1)。
②對於動態規劃:思路和法①基本接近。只不過乙個是遞迴實現,乙個是迴圈遞推實現,可以根據①來設計主要的核心演算法:
偽語言描述:
if 當前剩餘容積i《第j個物品大小v[j]dp[i][j] = dp[i][j-1];//
不放第j個物品的放法,容積不夠只能不選
else
if 當前剩餘容積i>=第j個物品大小v[j] //
容積足夠
dp[i][j] =dp[i][j-1]+dp[i - v[j]][j - 1]; //
對第j個物品選擇和不選擇兩種做法 方法數加和
遞迴實現**:
#include#includeint a[30
]; int way(int x,int
n)int
main()
//時間複雜度o(2^n)
dp實現**:
#include#include#include
using
namespace
std;
intmain()
memset(dp,
0, sizeof
(dp));
//邊界條件:有物品,湊出體積為0的做法為1(乙個物品都不放)
for (int i = 0; i <= n; ++i)
for(int i = 1;i<=40;++i)
for (int j = 0; j <= n; ++j)
}cout
<< dp[40][n]
}
百練 2755 神奇的口袋
描述 有乙個神奇的口袋,總的容積是40,用這個口袋可以變出一些物品,這些物品的總體積必須是40。john現在有n個想要得到的物品,每個物品的體積分別是a 1,a2 a n。john可以從這些物品中選擇一些,如果選出的物體的總體積是40,那麼利用這個神奇的口袋,john就可以得到這些物品。現在的問題是...
百練 2755 神奇的口袋
遞迴 include include include includeusing namespace std const int maxn 30 int n,d maxn int dp int w,int n int main 人人為我動歸 狀態定義 揹包容量為i時,選完前j件物品後,能達到該容量的最...
百練 2755 神奇的口袋
第一種解法是很經典的動態規劃,對於值域較小的題目,還可以採用第二種方法,考慮對值域空間 即對容積的可達性進行動態規劃。這道題裡面採用第二種解法還會有空間上的優化。有時把值域作為一種狀態不單單是一種解法,還有可能是唯一的解法。如hdu 1574 rp問題 描述有乙個神奇的口袋,總的容積是40,用這個口...