数字和为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 }

 


posted @ 2017-08-29 10:16  hedgehog小子  阅读(324)  评论(0编辑  收藏  举报