AcWing 532. 货币系统

题目描述

在网友的国度中共有n种不同面额的货币,第 i 种货币的面额为a[i],你可以假设每一种货币都有无穷多张。

为了方便,我们把货币种数为n、面额数组为a[1..n]的货币系统记作(n,a) 。 

在一个完善的货币系统中,每一个非负整数的金额 x 都应该可以被表示出,即对每一个非负整数 x,都存在 nn 个非负整数 t[i] 满足 a[i]*t[i] 的和为 x

然而,在网友的国度中,货币系统可能是不完善的,即可能存在金额 x 不能被该货币系统表示出。

例如在货币系统 n=3,a=[2,5,9] 中,金额 1,3 就无法被表示出来。 

两个货币系统 (n,a) 和 (m,b) 是等价的,当且仅当对于任意非负整数 x,它要么均可以被两个货币系统表出,要么不能被其中任何一个表出。 

现在网友们打算简化一下货币系统。

他们希望找到一个货币系统 (m,b),满足 (m,b) 与原来的货币系统 (n,a) 等价,且 m 尽可能的小。

他们希望你来协助完成这个艰巨的任务:找到最小的 m

输入格式

输入文件的第一行包含一个整数 T,表示数据的组数。

接下来按照如下格式分别给出 T 组数据。 

每组数据的第一行包含一个正整数 n

接下来一行包含 n 个由空格隔开的正整数 a[i]

输出格式

输出文件共有 T 行,对于每组数据,输出一行一个正整数,表示所有与 (n,a) 等价的货币系统 (m,b) 中,最小的 m

数据范围

\[1 \leq n \leq 100\]

\[1 \leq a[i]\leq 25000\]

\[1 \leq T \leq 20\]

输入样例

1
2
3
4
5
2 
4
3 19 10 6
5
11 29 13 19 17

输出样例

1
2
2
5

题目思路

本题中的货币系统实际上就是在给定的一串数字中去掉所有的可以被其他任意数字表示出的数字。故可以考虑使用动态规划求出使用该列数字可以表出的所有数字的方案数量,当且仅当给出数字的表示方案数量大于1的时候,即该数字除了可以被自己表出还可以被其他数字组合表出的时候即可以去掉。

根据以上思路该题将会退化为一个完全背包组合问题,代码实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 25010, CNT = 101;

int T, n;
int a[CNT];long long f[N];

int main()
{
cin >> T;
while(T--)
{
fill(f, f + N, 0);
f[0] = 1;
cin >> n;
int mx = 0, res = n;
for (int i = 1; i <= n; ++i)
{
cin >> a[i]; mx = max(a[i], mx);
}

for (int i = 1; i <= n; ++i)
{
for (int j = a[i]; j <= mx; ++j) f[j] += f[j - a[i]];
}

for (int i = 1; i <= n; ++i)
{
if (f[a[i]] > 1) res--;
}
cout << res << endl;
}
}

AcWing 532. 货币系统
http://anyin233.github.io/2021/05/22/AcWing-532/
Author
anyin233
Posted on
May 22, 2021
Licensed under