給定n個正整數a1,a2,…,an,從中選出若干個數,使它們的和為m,求有多少種選擇方案。
輸入格式
第一行包含兩個整數n和m。
第二行包含n個整數,表示a1,a2,…,an。
輸出格式
包含乙個整數,表示可選方案數。
資料範圍
1≤n≤100,
1≤m≤10000,
1≤ai≤1000
輸入樣例:
4 4
1 1 2 2
輸出樣例:
3
思路:
這個問題可以轉化為:從n件物品(數字)中選若干個,使之和恰好為為m的方案個數,每個數都是只有選和不選兩種決策,顯然可以把這個問題看作乙個01揹包求方案數的問題,從狀態表示和狀態計算兩方面分別分析:
狀態表示:集合:用f[i,j]表示選前i個物品,且體積恰好為j的方案,維護的屬性為count(個數)。
狀態計算等價於集合劃分的過程,將f[i,j]按照最後乙個物品(當前的i)選和不選,可以劃分為兩塊,一塊為選第i件,另一塊為不選第i件。
不選第i件:f[i,j]=f[i-1,j]
選第i件:f[i,j]=f[i-1,j-vi](vi表示當前第i個數的數值,選第i件之後會有兩部分構成,因為是求方案數,因此兩部分是乙個方案,方案數等價,所以只分析去掉地i件的前一部分的方案數即可)
因此,最後f[i,j]=f[i-1,j]+f[i-1,j-vi],可以發現轉態轉移中當前i狀態只和i-1轉態有關,所以可以從大到小列舉體積(這裡是數值),就可以保證每個狀態都只考慮一次,不會重複計算,所以就可以省去一維,用f[i]表示選前i個數的方案即可。
完整**:
#include #include #include using namespace std;
const int maxn=10010;
int f[maxn];
int main()
cout
}
數字組合(01揹包問題)
給定n個正整數a1,a2,an,從中選出若干個數,使它們的和為m,求有多少種選擇方案。輸入格式 第一行包含兩個整數n和m。第二行包含n個整數,表示a1,a2,an。輸出格式 包含乙個整數,表示可選方案數。資料範圍 1 n 100 1 m 10000 1 ai 1000 輸入樣例 44 1122 輸出...
數字組合(01揹包)
小蒜有n 1 n 20 個正整數,找出其中和為t t 也是正整數 的可能的組合方式。如 n 5,5 個數分別為 1,2,3,4,5 t 5 那麼可能的組合有 5 1 4 5 1 4 和 5 2 3 和 5 5三種組合方式。輸入格式 輸入的第一行是兩個正整數 n 和 t,用空格隔開,其中1 n 20,...
數字組合(01揹包)
就是01揹包小小變形一下就不太會做了。思路 當前和的方案數等於當前和減當前和當去當前正數的方案數,如 當前正數為2,和為5的方案數就等於3 5 2 的方案數,和為3的方案數又等於1 3 2 的方案數。又因為在每一種方案中每個數字只能使用一次,所以採用01揹包。狀態轉移方程式 dp j dp j w ...