P1164 小A点菜——记忆化搜索,递推与递归

题目背景

uim 神犇拿到了 uoi 的 ra(镭牌)后,立刻拉着基友小 A 到了一家……餐馆,很低端的那种。

uim 指着墙上的价目表(太低级了没有菜单),说:“随便点”。

题目描述

不过 uim 由于买了一些书,口袋里只剩 M(M10000)

餐馆虽低端,但是菜品种类不少,有 N(N100),第 i 种卖 ai(ai1000)。由于是很低端的餐馆,所以每种菜只有一份。

小 A 奉行“不把钱吃光不罢休”的原则,所以他点单一定刚好把 uim 身上所有钱花完。他想知道有多少种点菜方法。

由于小 A 肚子太饿,所以最多只能等待 1 秒。

输入格式

第一行是两个数字,表示 NM

第二行起 N 个正数 ai(可以有相同的数字,每个数字均在 1000 以内)。

输出格式

一个正整数,表示点菜方案数,保证答案的范围在 int 之内。

输入输出样例 #1

输入 #1

4 4
1 1 2 2

输出 #1

3

说明/提示

2020.8.29,增添一组 hack 数据 by @yummy

超时解法

for循环暴力&无记忆

#include <bits/stdc++.h>
using namespace std;
int a[1001];
int mycount=0;
int n,m;
void dfs(int index,int money) {
if(money==0) {
mycount++;
return;
}
for (int i=index;i<n;i++) {
dfs(i+1,money-a[i]);
}
}
int main() {
cin>>n>>m;
for (int i=0;i<n;i++) {
cin>>a[i];
}
dfs(0,m);
cout<<mycount;
}

题解

最小事件:选择/不选择;记忆化搜索

#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 105;
const int MAXM = 10010;
int a[MAXN];
int n, m;
int mem[MAXN][MAXM];
// 记忆化搜索函数
int dfs(int index, int money) {
// 如果剩余钱为 0,说明刚好花完,返回 1
if (money == 0) {
return 1;
}
// 如果剩余钱小于 0 或者已经遍历完所有菜品,返回 0
if (money < 0 || index == n) {
return 0;
}
// 如果已经计算过该状态,直接返回结果
if (mem[index][money] != -1) {
return mem[index][money];
}
// 不选择当前菜品
int res = dfs(index + 1, money);
// 选择当前菜品
res += dfs(index + 1, money - a[index]);
// 记录当前状态的结果
mem[index][money] = res;
return res;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
// 初始化记忆化数组
memset(mem, -1, sizeof(mem));
cout << dfs(0, m) << endl;
return 0;
}
发布于   xiins  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示