[完全背包] NOIP2018 货币系统

[完全背包] NOIP2018 货币系统


题面

题目描述

在网友的国度中共有\(n\)种不同面额的货币,第\(i\)种货币的面额为\(a[i]\),你可以假设每一种货币都有无穷多张。为了方便,我们把货币种数为\(n\)、面额数组为\(a[1..n]\)的货币系统记作\((n,a)\)

在一个完善的货币系统中,每一个非负整数的金额\(x\)都应该可以被表示出,即对每一个非负整数\(x\),都存在\(n\)个非负整数\(t[i]\)满足\(a[i] \times 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\)

Sample Input

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

Sample Output

2
5


题解

我们先证明一个结论:

那么要使\(m\)最小,\((m,b)\)中的每一个元素必定存在于\((n,a)\)

下面给出这个结论的证明:

假设\((m,b)\)中包含一个不存在于\((n,a)\)中的元素
则有两种情况:

  1. 这个元素可以被\((n,a)\)中的元素表示,那么此时\(m\)不满足最小,因为这个元素可以被剔除
  2. 这个元素不能被\((n,a)\)中的元素表示,那么此时不满足\((n,a)\)\((m,b)\)等效

所以\((m,b)\)中不包含任何不存在于\((n,a)\)中的元素

那么我们就可以直接从\((n,a)\)中剔除可以被自己表示的元素就可以得到\((m,b)\)

只需要背包一下就行了,思路还是很清晰的

上代码:

#include<bits/stdc++.h>

using namespace std;

const int MAXN=30001;

int n,ans,t,maxn=0,a[MAXN],vis[MAXN];
bool tf[MAXN],dp[MAXN];//tf[i]表示数字i是否出现在(n,a)中
                       //dp[i]表示数字i是否可以被(n,a)表示

int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);ans=n;
        memset(vis,0,sizeof(vis));
        memset(tf,0,sizeof(tf));
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){scanf("%d",&a[i]);tf[a[i]]=true;maxn=max(maxn,a[i]);}
        sort(a+1,a+1+n);
        dp[0]=true;
        for(int i=a[1];i<=maxn;i++){
            for(int j=1;j<=vis[0];j++)if(dp[i-vis[j]])dp[i]=true;//背包
            if(dp[i]){
                    if(tf[i])ans--;//如果可以被表示,则剔除
            }else{
                if(tf[i]){vis[++vis[0]]=i;dp[i]=1;}//否则用它来表示其他的数值
            }
        }
        printf("%d\n",ans);
    }
}

posted @ 2018-11-21 13:13  Remilia_Saikou  阅读(169)  评论(0编辑  收藏  举报