题目:
有n个正整数,找出其中和为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
题意分析:
由于这题的 n 值范围比较小,可以进行搜索枚举
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=500005;
int data[maxn];
int total=0,sum=0,n,t;
void dfs(int x)
{
if(sum==t)
{
total++;
return;
}
if(x<n)
{
for(int i=0; i<2; i++)
{
if(i==0)
sum+=data[x];
if(i==1)
sum-=data[x];
dfs(x+1);
}
}
}
int main()
{
scanf("%d %d",&n,&t);
for(int i=0; i<n; i++)
scanf("%d",&data[i]);
dfs(0);
printf("%d\n",total);
return 0;
}
还可以用dp优化,类似于01背包问题,dp[i][j]表示前i个数之和为j的个数
#include<iostream>
using namespace std;
int n,t,data[30];
int dp[30][1100];
int main()
{
cin>>n>>t;
for(int i=1; i<=n; i++)
cin>>data[i];
for(int i=1; i<=n; i++)
{
for(int j=1; j<=t; j++)
{
if(j==data[i]) //令dp[i][j]=1是递推关键
{
dp[i][j]=1;
}
if(j>=data[i])
{
dp[i][j]+=dp[i-1][j]+dp[i-1][j-data[i]]; //前i个数组合成j的情况:自身情况+上一个i不加a[i]的情况+上一个i加入a[i]的情况
}
else
{
dp[i][j]=dp[i-1][j];
}
}
}
cout<<dp[n][t]<<endl;
}