你好!
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
/*
分析:这是一个动态规划问题:
a. "01背包"——每种菜只有"点或者不点"2个选择,每种菜只有一盘
b. 滚动数组——因为YS1到10000,N到100,不压缩存储的话dp太大
c. 恰好装满——要求YS1元钱必须恰好用完
d. 方案个数——求点菜方案的个数,不是求最大值
例如:dp[10] = 3 表示要恰好用完10元钱,可以有3种点菜方案
1. 状态转移方程
dp[v] = dp[v] + dp[v-ys1[i]]
2. 填写顺序:
i:[1..N]
v:[YS1, ys1[i]] (如果此处是增序,则变成重复背包了)
3. 初值:
dp[i] = 0 i:[1..YS1]
设置为0,本题求方案个数,不需要设置成NINF
dp[0] = 1
如果一共有0元,那么,"什么都不点"也是1种方案,刚好用完0元
4. 结果分析:
(1) 根据题意,要输出dp[YS1]的值,
即刚好用完YS1元的点菜方案个数
(2) 如果dp[i] = 0 ,则表示没办法刚好用完i元
更详细的分析,请看课件
*/
//
int dp[10001];
int ys1[101];
int N, YS1;
int main()
{
cin >>N >>YS1;
for (int i=1; i<=N; i++) scanf("%d", &ys1[i]);
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for(int i=1;i<=N;i++)
{
for(int v=YS1;v>=ys1[i];v--) // v不够w[i]的话,dp[v]不会改变。
{
dp[v] = dp[v] + dp[v-ys1[i]];
}
}
printf("%d", dp[YS1]);
return 0;
}