P1164 小A点菜 - 洛谷 | 计算机科学教育新生态
题目背景
uim 神犇拿到了 uoi 的 ra(镭牌)后,立刻拉着基友小 A 到了一家……餐馆,很低端的那种。
uim 指着墙上的价目表(太低级了没有菜单),说:“随便点”。
题目描述
不过 uim 由于买了一些书,口袋里只剩 M 元(M ≤ 10000)。
餐馆虽低端,但是菜品种类不少,有 N 种(N ≤ 100),第 i 种卖 a_i 元(a_i ≤ 1000)。由于是很低端的餐馆,所以每种菜只有一份。
小 A 奉行“不把钱吃光不罢休”的原则,所以他点单一正好把 uim 身上所有钱花完。他想知道有多少种点菜方法。
由于小 A 肚子太饿,所以最多只能等待 1 秒。
输入格式
第一行是两个数字,表示 N 和 M。
第二行起 N 个正数 a_i(可以有相同的数字,每个数字均在 1000 以内)。
输出格式
一个正整数,表示点菜方案数,保证答案的范围在 int 之内。
输入输出样例
输入 #1
4 4
1 1 2 2
输出 #1
3
说明/提示
2020.8.29,增添一组 hack 数据 by @yummy
思路:
代码如下:
记忆化搜索:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e4 + 10;
int n, m;
int value[N];
int mem[N][N]; // 表示第 i 个物品,剩余 j 时的方案数
int dfs(int x, int SP)
{
//cout << x << "------" << SP << endl;
int sum = 0;
if (mem[x][SP])
return mem[x][SP];
if (SP == 0)
return 1;
if (x > n)
return 0;
if (SP >= value[x])
sum = dfs(x + 1, SP - value[x]) + dfs(x + 1, SP);
else
sum = dfs(x + 1, SP);
mem[x][SP] = sum;
return sum;
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> value[i];
}
memset(mem, 0, sizeof(mem));
cout << dfs(1, m);
return 0;
}
dp:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e4 + 10;
int n, m;
int value[N];
int f[N][N]; // 表示第 i 个物品,剩余 j 时的方案数
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> value[i];
}
f[n+1][0] = 1;
for(int i = n ; i >= 1 ; i--)
{
for(int j = 0 ; j <= m ; j++)
{
if(j >= value[i])
f[i][j] = f[i+1][j-value[i]] + f[i+1][j];
else
f[i][j] = f[i+1][j];
}
}
cout << f[1][m];
return 0;
}
dp2:
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e4 + 10;
int n, m;
int value[N];
int dp[N][N]; // dp[i][j] 表示前 i 个物品,背包容量为 j 时的方案数
int main() {
cin >> n >> m;
// 输入物品价值
for (int i = 1; i <= n; i++) {
cin >> value[i];
}
// 初始化 dp 数组
memset(dp, 0, sizeof(dp));
dp[0][0] = 1; // 没有物品时,背包容量为 0 的方案数为 1
// 动态规划计算
for (int i = 1; i <= n; i++)
{
for (int j = 0; j <= m; j++)
{
if (j >= value[i])
dp[i][j] = dp[i-1][j - value[i]] + dp[i-1][j]; // 选择当前物品
else
dp[i][j] = dp[i-1][j]; // 不选择当前物品
}
}
// 输出结果
cout << dp[n][m];
return 0;
}