NC21228 货币系统(5月27日 完全背包)

NC21228 货币系统

题目链接

题目大意
给出一个包含 n n 个不同面值的货币系统,最少要多少种货币能表示出原货币系统能表示的所有面额。

输入
2
4
3 19 10 6
5
11 29 13 19 17
输出
2
5
说明
在第一组数据中,货币系统(2, [3,10])和给出的货币系统(n, a)等价,并可以验证不存在m < 2的等价的货币系统,因此答案为2。
在第二组数据中,可以验证不存在m < n的等价的货币系统,因此答案为5。
备注:
1 <= T <= 20, 1 <= n <= 100, 1 <= a[i] <= 25000

分析:
我们可以把这个货币系统能表示出的所有面额都求出来,从这些面额中选取一部分,如果同样能把所有面额都表示出来,那么就是与原货币系统等价的。再想,那些不在货币系统中的面额都是从中被表示出来的,这些就是多余的,不能选它们,那么同样货币系统中的那些可以由其它货币表示出来的也不能选。所以,最后问题就变成了在货币系统中哪些数能被其它数组成,剩下的数就是最小集合,货币无限次,这就是完全背包, f [ i ] f[i] 表示能否组成 i i ,如果等于1表示可以,如果等于0表示不能组成,就记录到答案中。

Code:

// https://ac.nowcoder.com/acm/problem/21228
#include <bits/stdc++.h>
using namespace std;
int a[110];
bool dp[25010]; //完全背包,大的币能否被小的币表示出
int main() {
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) cin >> a[i];
        sort(a + 1, a + n + 1);
        memset(dp, 0, sizeof(dp));
        dp[0] = 1;
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            if (dp[a[i]]) continue;
            ans++;
            for (int j = a[i]; j <= 25000; j++)
                dp[j] |= dp[j - a[i]];
        }
        cout << ans << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44169557/article/details/106443886