程式設計題——和為sum的方法數
阿新 • • 發佈:2019-01-03
題目描述
給定一個有n個正整數的陣列A和一個整數sum,求選擇陣列A中部分數字和為sum的方案數。當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。
輸入描述:
輸入為兩行: 第一行為兩個正整數n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000) 第二行為n個正整數A[i](32位整數),以空格隔開。
輸出描述:
輸出所求的方案數示例1
輸入
5 15 5 5 10 2 3
輸出
4
思路一:
用遞迴加回溯的方法,找出陣列的所有子集。
若子集和等於整數sum,則陣列A中部分數字和為sum的方案數加一。
可優化的地方在子集當前和大於sum,則跳出該分支,因為陣列A為正整數,之後的子集和只會越來越大。
這種方法缺點在於:時間複雜度大,為 O(2 ^ n) ,遞迴呼叫次數過多,容易爆棧。
#include<iostream> #include<vector> using namespace std; int n, sum, count = 0; void help(vector<int>& a, int pos, int part) { if (part == sum) count++; if (part > sum) return; for(int i=pos; i<n; i++) { part += a[i]; help(a, i+1, part); part -= a[i]; } } int main(){ cin>>n>>sum; vector<int> a(n); for(int i=0; i<n; i++) cin>>a[i]; help(a, 0, 0); cout<<count<<endl; return 0; }
思路二:
用動態規劃,類似01揹包問題,f(i , j )表示前i 個數中和為 j 的方案數, 則 若 j >= a[i], f ( i ,j) = f(i -1, j)+ f (i - 1,j - a[i] );
否則, f ( i ,j) = f(i -1, j)。
可優化地方:由於二維陣列中,第i行 只與第 i - 1 行有關,所有我們若從 最後一列 開始更新陣列,則可用一維陣列來儲存先前狀態。
時間複雜度為:O( n * sum ) 。
#include<iostream> #include<vector> using namespace std; int main() { int n, sum; cin>>n>>sum; vector<long long> a(sum+1); vector<int> b(n); for(int i=0; i<n; i++) cin>>b[i]; a[0] = 1; for (int i=0; i<n; i++) for (int j=sum; j>=b[i]; j--) a[j] += a[j-b[i]]; cout<<a[sum]<<endl; return 0; }