luogu P5020ybtoj背包问题课堂过关DP例题2货币系统 & NOIP2018 提高组货币系统
Posted SSL_ZZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P5020ybtoj背包问题课堂过关DP例题2货币系统 & NOIP2018 提高组货币系统相关的知识,希望对你有一定的参考价值。
Link
luogu P5020 [NOIP2018 提高组] 货币系统
ybtoj 【背包问题课堂过关】【例题2】货币系统
题面//因为不知道侵不侵权所以就是题面是私密的,有账号的直接看转送门就可了
题目大意
给你一些数字,这堆数字无论哪个数选多少个都可以,然后就会有一些数能凑出,一些不能。
要你再找一堆尽可能少的数字,使得它像前面那样的情况下 能凑出的 和 不能凑出的 是一模一样的。
输出你找的这堆最少个数的数字的个数。
样例输入
2
4
3 19 10 6
5
11 29 13 19 17
样例输出
2
5
解题思路
首先,能凑出的 和 不能凑出的 是一模一样的,当然考虑两组数一模一样
稍微分析一下第一组,就会发现,如果别的数可以组成当前数,那么当前数就不必要
(6 = 2 * 3;19 = 3 * 3 + 10,所以答案为2)
设
f
[
x
]
f[x]
f[x]为最多用多少个数能组成
x
x
x
f
[
x
]
=
m
a
x
(
f
[
x
]
,
f
[
x
−
a
[
i
]
]
+
1
)
f[x]=max(f[x], f[x - a[i]]+1)
f[x]=max(f[x],f[x−a[i]]+1)
(然后发现就是个完全背包…)
Code
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int T, n, m, ans, f[100100], a[100100];
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) {
for(int j = a[i]; j <= 25000; j++) //完全背包=>正序
if(f[j - a[i]] || j == a[i]) //f[j-a[i]]=>因为必须在可建的背景下,才可以转移
//比如,数为(5,2),不能f[6-2]+1,因为根本不能建成4
f[j] = max(f[j], f[j - a[i]] + 1);
}
for(int i = 1; i <= n; i++)
if(f[a[i]] == 1) ans++;
printf("%d\\n", ans);
ans = 0;
memset(f, 0, sizeof(f));
}
}
以上是关于luogu P5020ybtoj背包问题课堂过关DP例题2货币系统 & NOIP2018 提高组货币系统的主要内容,如果未能解决你的问题,请参考以下文章
luogu P4514ybtoj树状数组课堂过关差分 例题6区间修改区间查询 & 上帝造题的七分钟
luogu P4513ybtoj线段树课堂过关例题3小白逛公园
ybtoj 单调队列课堂过关luogu P1886例题1滑动窗口