NOIP2018提高組 貨幣系統 揹包問題求方案數變形

題目描述
在網友的國度中共有 n 種不同面額的貨幣,第 i 種貨幣的面額爲 a[i],你可以假設每一種貨幣都有無窮多張。

爲了方便,我們把貨幣種數爲 n、面額數組爲 a[1…n] 的貨幣系統記作 (n,a)。

在一個完善的貨幣系統中,每一個非負整數的金額 x 都應該可以被表示出,即對每一個非負整數 x,都存在 n 個非負整數 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≤n≤100,
1≤a[i]≤25000,
1≤T≤20
輸入樣例:
2
4
3 19 10 6
5
11 29 13 19 17
輸出樣例:
2
5
思路

有3個性質:

  1. a1, s2, a3…an 一定能被表示出來
  2. b1 b2, b3 … bn 一定不能被b序列裏面的數表示出來: 因爲如果可以表示出來, 那麼這個bi就可以刪除掉
  3. b序列一定是從a序列裏面選的: 如果不是a序列裏面選的, 所以它一定可以由a序列表示出來, 而a和b是等價的, 所以它一定可以由b表示出來, 所以它和第二個性質一樣, 是可以刪除掉的

有了這3個性質, 我們可以得到結果是a序列中的不能被其他數表示出來的數, 就是我們要求得b序列

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110, M = 25010;

int a[N], f[M];
int n;

int main()
{
    int t;
    cin >> t;
    while(t--)
    {
        cin >> n;
        memset(f, 0, sizeof f);
        for(int i = 1; i <= n; i++)
            cin >> a[i];
        
        sort(a + 1, a + 1 + n);
        f[0] = 1;
        int ans = 0;
       int m = a[n];
        for(int i = 1; i <= n; i++)
        {
            if(f[a[i]] == 0)
                ans++;
            for(int j = a[i]; j <= m; j++)
                f[j] = f[j] + f[j - a[i]];
        }
        cout << ans <<endl;
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章