题意
给无限个10,20,50,100的硬币,以及n(<=100)个价格,问最少带多少硬币能表示任意一个价格。
思路
10元硬币一定不超过1个,20元不超过4个,50元不超过1个。枚举每种硬币出现的次数,做一次01背包求出那些价格可以被表示,能拼出的价格范围在0~140之间。对于每个价格w,取x=w%100,如果100+x能被表示,就最少需要w/100-1个100元硬币,如果x能被表示就最小需要w/100个100元硬币,否则就不能被表示。
#include<bits/stdc++.h>
using namespace std;
int n;
int a[105],b[105];
int f[305];
int solve(int x,int y,int z)
{
int num=0;
for (int i=1;i<=x;i++) b[++num]=10;
for (int i=1;i<=y;i++) b[++num]=20;
for (int i=1;i<=z;i++) b[++num]=50;
memset(f,0,sizeof(f));
f[0]=1;
for (int i=1;i<=num;i++)
{
for (int j=150;j>=0;j-=10)
{
if (f[j]) f[j]=1;
if (j-b[i]>=0&&f[j-b[i]]) f[j]=1;
}
}
int cur=0;
for (int i=1;i<=n;i++)
{
if (a[i]<=150&&f[a[i]]) continue;
if (f[a[i]%100+100])
{
cur=max(cur,a[i]/100-1);
continue;
} else
if (f[a[i]%100]) cur=max(cur,a[i]/100); else return 1000000000;
}
return cur+x+y+z;
}
int main()
{
int T;
scanf("%d",&T);
while (T--)
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
bool jud=0;
for (int i=1;i<=n;i++)
{
if (a[i]%10) jud=1;
}
if (jud)
{
printf("-1
");
continue;
}
int ans=1000000000;
for (int i=0;i<=1;i++)
{
for (int j=0;j<=4;j++)
{
for (int k=0;k<=1;k++)
{
ans=min(ans,solve(i,j,k));
}
}
}
printf("%d
",ans);
}
return 0;
}