数字和为sum的方案数
【问题描述】
给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。
当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。
【输入输出】
输入为两行:
第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)
第二行为n个正整数A[i](32位整数),以空格隔开。
输出:
所求的方案数
【算法思路】
方法1:很巧妙。每次读取一个数组元素,并更新sum数组。
方法2:动态规划。用 dp[ i ][ j ] 表示用前 i 个值组成和为 j 的方案个数,递推式可以很容易列出来。特别注意,和之前的DP问题不同的是,这里的DP矩阵并不需要依次全部求出来,只需要求需要的就可以了,具体见程序。
方法3:递归分治法。笨笨的。
【代码】
方法1:
1 #include <iostream> 2 using namespace std; 3 4 int const maxn = 100; 5 int data[maxn]; 6 long long f[maxn]; //下标表示sum,值表示有几种可能 7 int main() { 8 int n,sum; 9 cin>>n>>sum; 10 int *data = new 11 for (int i=1;i<=n;i++) { 12 cin>>data[i]; 13 } 14 15 //可以对下面的代码举个例子,就容易懂了 16 f[0] = 1; //初始化 17 for (int i=1;i<=n;i++) { 18 for (int j=sum;j>=0;j--) { 19 if(j>=data[i]) { 20 f[j] += f[j-data[i]]; //关键一步 21 } 22 } 23 } 24 cout<<f[sum]<<endl; 25 }
方法2:
1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 //递归会超时,只能过40%,用dp. dp[i][j]表示用前i个值组成和为j的方案个数 5 //注意:最终结果int类型存不下,需要64位数据 6 //注意:dp不能放在main里,栈存不下。需要存在全局数据区 7 long long dp[1001][1001]; 8 9 int main() 10 { 11 int n; 12 int A[1001]={0}; 13 int sum; 14 while(scanf("%d %d", &n, &sum) != EOF) { 15 for(int i = 1; i<=n; i++){ 16 scanf("%d", A + i); 17 } 18 // 重要的预处理,可以自己尝试几个就知道了 19 for(int j = 1; j <= sum; j++){ 20 dp[0][j] = 0; 21 } 22 for(int i = 1; i <= n; i++){ 23 dp[i][0] = 1; 24 } 25 dp[0][0] = 1; 26 27 // dp 28 for(int i = 1; i <= n; i++){ 29 for(int j = 1; j <= sum; j++) { 30 dp[i][j] = dp[i - 1][j]; 31 if(j >= A[i]) { 32 dp[i][j] += dp[i-1][j-A[i]]; 33 } 34 } 35 } 36 37 printf("%lld\n", dp[n][sum]); 38 } 39 return 0; 40 }
方法3:
1 #include<iostream> 2 #include<vector> 3 #include<stdio.h> 4 using namespace std; 5 6 int times=0; 7 void findsum(int arr[], int s, int e, int sum) 8 { 9 if(sum==0){ 10 times++; 11 return; 12 }else if(sum<0){ 13 return; 14 } 15 16 if(s<=e){ 17 findsum(arr, s+1, e, sum-arr[s]); 18 findsum(arr, s+1, e, sum); 19 } 20 } 21 22 int main(){ 23 24 int n, number; 25 scanf("%d %d", &n, &number); 26 int* arr = new int[n]; 27 for(int i=0; i<n; i++){ 28 scanf("%d", &(arr[i])); 29 } 30 31 findsum(arr, 0, n-1, number); 32 33 cout<<times<<endl; 34 return 0; 35 }