数字和为sum的方法数
1.题目描述
给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。
输入描述:
输入为两行:
第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)
第二行为n个正整数A[i] ( 32位整数),以空格隔开。
输出描述:
输出所求的方案数
示例1
2.思路(动态规划)
(1)递推关系为:dp[i][j] = dp[i-1][j] + dp[i-1][j-A[i]]
dp[i-1][j]:表示不用第i个数字能凑到j的最多情况
dp[i-1][j-value[i]]:用了i时,原来凑到j-value[i]的最多情况
(2)两个相加dp[i][j]代表用前i个数字凑到j最多有多少种方案。
其中i表示数组下标,j表示和为j,由于递推关系dp[i][j]只与i-1有关,因此空间复杂度可以优化为O(n),即dp[j] = dp[j] + dp[j-A[i]],表示组合成j的方法总数等于取到当前数子A[i]时组合成j-A[i]的方法总数加上没有取到当前数字A[i]时的方法总数。
(3)dp[0]=1; //初始化,表示凑到0永远有1种方案(什么数都不取)。
3.代码
#include <iostream>
#include <vector>
using namespace std;
int main(){
int n = 0, sum = 0;
cin >> n >> sum;
vector<int> nums(n);
vector<long> dp(sum+1);
for(int i = 0;i < n;++i){
cin >> nums[i];
}
dp[0] = 1;//组合成0有一种方法,即取0个数
for(int i = 0;i < n;++i){
for(int j = sum;j >= nums[i];--j){
dp[j] += dp[j-nums[i]];
}
}
cout << dp[sum] << endl;
return 0;
}
4.复杂度分析
时间复杂度:O(n^2)
空间复杂度:O(n)