P5020 货币系统 (NOIP2018)

传送门

BFS解法

显然如果一个面额A可以被其他面额表示出来

那么这个面额A就没用了

且如果A不能被其他面额表示,那么A一定有用(A本身的值只有自己可以表示)

发现面额最大不超过 25000

那么设 p [ i ] 表示面额 i 能否被其他面额表示

然后跑BFS求 p 就好了

注意初始状态是每两个数相加的值

因为自己表示自己不合法,且每种面额都是不同的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=207,M=5e4+7;
int T,n,a[N],mx,ans;
bool p[M];
queue <int> q;
void BFS()//BFS求p
{
    for(int i=0;i<=mx;i++) p[i]=0;
    int x=0,t=0;
    for(int i=1;i<=n;i++)
        for(int j=i;j<=n;j++)
        {
            t=a[i]+a[j]; if(t>mx||p[t]) continue;
            p[t]=1; q.push(t);//初始时是每两种面额相加
        }
    while(!q.empty())
    {
        x=q.front(); q.pop();
        for(int i=1;i<=n;i++)
        {
            t=x+a[i]; if(t>mx||p[t]) continue;
            p[t]=1; q.push(t);
        }
    }
}
int main()
{
    freopen("money.in","r",stdin);
    freopen("money.out","w",stdout);
    T=read();
    while(T--)
    {
        n=read(); mx=ans=0;
        for(int i=1;i<=n;i++) a[i]=read(),mx=max(mx,a[i]);
        BFS();
        for(int i=1;i<=n;i++) if(!p[a[i]]) ans++;//算有多少种面额不能表示
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-12-05 21:19  LLTYYC  阅读(180)  评论(0编辑  收藏  举报