1. 程式人生 > 實用技巧 >【完全揹包】B000_AW_貨幣系統(分析題意)

【完全揹包】B000_AW_貨幣系統(分析題意)

在網友的國度中共有 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

方法一:dp(方案數)

還是題意比較難:讓我們儘量讓系統的貨幣數儘量少,也就是讓我們刪除一些可有可無的面值,也就是說一個原有的面值 x 的表示方案如果多於 1 種,那麼該面值 x 可以刪除

#include<bits/stdc++.h>
using namespace std;
const int N=25005;

int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t; cin>>t;

    while (t--) {
        int n, m=0; cin>>n;
        int A[n], f[N]; 
        memset(f, 0, sizeof f); f[0]=1;
        for (int i=0; i<n; i++) cin>>A[i], m=max(m, A[i]);

        for (int x : A)
        for (int j=x; j<=m; j++)
            f[j]+=f[j-x];

        int c=0;
        for (int x : A) if (f[x]==1)
            c++;
        cout << c << '\n';
    }
    return 0;
}

複雜度分析

  • Time\(O(nm)\)
  • Space\(O(m)\)