欢迎光临
我们一直在努力

洛谷 P1164 小A点菜 简单直观的二维dp做法 C++

题目背景

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

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

题目描述

不过 uim 由于买了一些书,口袋里只剩 M 元 (0<M≤10000)。

餐馆虽低端,但是菜品种类不少,有 N 种 (1≤N≤100),第 i 种卖 ai​ 元 (0<ai​≤1000)。由于是很低端的餐馆,所以每种菜只有一份。

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

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

输入格式

第一行两个整数 N 和 M,分别表示菜品种类和 uim 身上的钱数。

第二行 N 个正整数 ai​(可能有重复),用空格隔开,分别表示每种菜的价格。

输出格式

一个正整数,表示点菜方案数,保证答案的范围在 [0,231−1] 之内(不超过 C/C++的 int 范围)。

输入输出样例

输入 #1

4 4
1 1 2 2

输出 #1

3

思路:

用二维动态规划,soyo[i][j] 表示前 i 种菜里选出若干种,总价恰好为 j 的方案数。

  • 对第 i 道菜,若价格超过 j,则不选它,方案数等于 soyo[i-1][j];
  • 若价格小于 j,则方案数为 “不选它的方案数” 加上 “选它(即前 i-1 道菜凑 j-saki[i] 的方案数)”;
  • 若价格正好等于 j,则在不选它的方案数基础上再加 1(单独选这道菜的情况)。

代码:

#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <vector>
#include <set>
#include <stack>
#include <string>
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#include <array>
#define ll long long
const ll N = 2e6 + 5;
const ll Max = 0x3f3f3f3f;
using namespace std;

ll n, m;

int main() {
cin >> n >> m;
vector<ll>saki(n + 1);
vector<vector<ll>>soyo(n + 1, vector<ll>(m + 1, 0));
for (int i = 1; i <= n; i++)cin >> saki[i];

for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (saki[i] > j)soyo[i][j] = soyo[i – 1][j];
if (saki[i] < j)soyo[i][j] = soyo[i – 1][j] + soyo[i – 1][j – saki[i]];
if (j == saki[i])soyo[i][j] = soyo[i – 1][j] + 1;
}
}
cout << soyo[n][m];

return 0;
}

赞(0)
未经允许不得转载:171主机测评 » 洛谷 P1164 小A点菜 简单直观的二维dp做法 C++
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址