題目描述
給定一個有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。
