问题 E: 序列操作Ⅰ
时间限制: 1 Sec 内存限制: 128 MB
[提交][状态][讨论版]
题目描述
给定长度为 N 的正整数序列 A_1, A_2, A_3,…, A_N, 从中选出若干个数,使它们的和是 M,求有多少种选择方案。
输入
第一行是两个数字,表示 N 和 M。(N,M<1000)
输出
一个数字,表示和为 M 的组合的个数。
样例输入
4 4
1 1 2 2
样例输出
3
提示
/*
很基础的01背包,画二维表就很容易得出状态转移方程。
要记住一开始要用最直观的方法写,
即不要一开始就用滚动数组空间优化,
要常规写法写好没有错误了再进行空间优化,
这样解题才不容易出错,思路也更清晰。
*/
开始最直观写法:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
int a[maxn];
int dp[maxn][maxn];
int main()
{
int n,m;
cin>>n>>m;
for(int i = 1; i <= n; i++)
{
cin>>a[i];
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(j-a[i]==0)
{
dp[i][j] = dp[i-1][j] + 1;
}
else if(j-a[i]<0)
{
dp[i][j] = dp[i-1][j];
}
else
{
dp[i][j] = dp[i-1][j] + dp[i-1][j-a[i]];
}
}
}
cout<<dp[n][m]<<endl;
return 0;
}
滚动数组空间优化及常数优化:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3+5;
int a[maxn];
int dp[maxn];
int main()
{
int n,m;
cin>>n>>m;
for(int i = 1; i <= n; i++)
{
cin>>a[i];
}
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= a[i]; j--)
{
dp[j]+=(j-a[i]==0?1:dp[j-a[i]]);
}
}
cout<<dp[m]<<endl;
return 0;
}