题目详情
小蒜有 n(1<=n<=20) 个正整数,找出其中和为 t(t 也是正整数)的可能的组合方式。如:
n=5,5 个数分别为 1,2,3,4,5,t=5;
那么可能的组合有 5=1+4和 5=2+3和 5=5三种组合方式。
输入格式
输入的第一行是两个正整数 n和 t,用空格隔开,其中 1≤n≤20, 表示正整数的个数,t为要求的和 (1≤t≤1000)
接下来的一行是 n 个正整数,用空格隔开。
输出格式
和为 t的不同的组合方式的数目。
输入示例
5 5
1 2 3 4 5
输出
3
题目分析与解法:这道题是一个简单的动态规划问题,我们定义dp[i][j]数组用来表示前i个数字能组合成j这个数的组合数,起初dp[0][0]=1,因为前0个数字组合成0的方案数就只有1组,就是什么都不选。然后接下来的各个状态就可以根据之前的已经求出来的状态结果进行转移了。
状态转移方程为dp[i][j]=dp[i-1][j],每一种状态由上一层状态转移,这是新来的那个数没有加上的情况,如果加上的话,就需要比较b这个数和j这个数大小,比如新输入的数为b,如果b>=j的话,转移方程就变成了dp[i][j]=dp[i-1][j]+dp[i-1][j-b]。
综上所述转移方程为,比如新输入的数为b,
if (j >= b)
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - b];
else
dp[i][j] = a[i - 1][j];
下面看代码
#include <bits/stdc++.h>
using namespace std;
int dp[21][1100]={0};
int main()
{
dp[0][0]=1;
int n,t;
cin>>n>>t;
int b;
for(int i=1;i<=n;i++)
{
cin>>b;
for(int j=0;j<=t;j++){
if(i==1&&b==j)
{
dp[i][j]=1;
}
else
{
if(j>=b)
{
dp[i][j]=dp[i-1][j-b]+dp[i-1][j];
}
else
dp[i][j]=dp[i-1][j];
}
}
}
cout<<dp[n][t]<<endl;
}