luogu P5020ybtoj背包问题课堂过关DP例题2货币系统 & NOIP2018 提高组货币系统

Posted SSL_ZZL

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P5020ybtoj背包问题课堂过关DP例题2货币系统 & NOIP2018 提高组货币系统相关的知识,希望对你有一定的参考价值。

【例题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[xa[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区间修改区间查询 & 上帝造题的七分钟

ybtoj背包问题课堂过关DP例题3宝物筛选

luogu P4513ybtoj线段树课堂过关例题3小白逛公园

ybtoj 单调队列课堂过关luogu P1886例题1滑动窗口

luogu UVA10559 ybtoj 区间DP课堂过关 例题3消除木块 & 方块消除 Blocks

luogu P4170ybtoj 区间DP课堂过关 例题2木板涂色 & [CQOI2007]涂色