題目描述
給定一個有n個正整數的數組A和一個整數sum,求選擇數組A中部分數字和為sum的方案數。
當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。
當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。
輸入描述:
輸入為兩行:
第一行為兩個正整數n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)
第二行為n個正整數A[i](32位整數),以空格隔開。
輸出描述:
輸入
5 15
5 5 10 2 3
輸出
4
#include<iostream> #include<vector> using namespace std; int main() { int n, sum; cin >> n >> sum; vector<long>vec(sum + 1, 0), input(n + 1, 0); vec[0] = 1;////這一步的目的是如果當前數字中的元素剛好等於要求的,就是多一種方法 //如果不賦值為1,還是為0就沒辦法加一種方法 vector<vector<long> >result(n + 1, vec); for (int i = 1; i <= n; i++) { cin >> input[i]; } //程序多加一行的目的是,例如:result[1][5]=result[0][5]+result[0][5-input[1]](即result[0][0]) //多加一行方便整體運算不需分類計算 for (int i = 1; i <= n; i++) { for (int j = 1; j <= sum; j++) { if (j - input[i] >= 0) { //如果列所在數字減去該行數大於等於0,該格子內容為該列上一行數字與上一行差 // 值所在格子數量和。什么意思呢?例如(10,3),若想要用3之前的數列得到10,除了 // 它上一行(即2)本身就能得到2個10外,只要之前的數字是7,7+3依然可以得到10。因 // 此去看上一行中列數為7的格子數值,為2,即它上一個數有2中組合得到7,7+3=10。 // 那該行數值即為2+2=4。 result[i][j] = result[i - 1][j] + result[i - 1][j - input[i]]; } else {//果列所在數字減去該行數小於0,那么該格子繼承本列上一行的數字。 result[i][j] = result[i - 1][j]; } } } cout << result[n][sum] << endl; return 0; }
如果是使用上面的用例圖解圖上圖所示,
然后說一下做法:
1.由於每個數總能把0填上,且0不可填上初0外其余數,所以數組第一行全填0,第一列全填1;
2.從第二行第二列開始遍歷數組。如果列所在數字減去該行數小於0,那么該格子繼承本列上一行的數字。例如圖中(2,10)對應格子。由於讓10得到2,那必須由-8+5得到,但是該題無法得到比0小的數,因此由10之前的數得到2的最多可能與他之前的數(即5)是一樣的;
3.如果列所在數字減去該行數大於等於0,該格子內容為該列上一行數字與上一行差值所在格子數量和。什么意思呢?例如(10,3),若想要用3之前的數列得到10,除了它上一行(即2)本身就能得到2個10外,只要之前的數字是7,7+3依然可以得到10。因 此去看上一行中列數為7的格子數值,為2,即它上一個數有2中組合得到7,7+3=10。
那該行數值即為2+2=4。