版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意:
Rikka手中有无数个面值为10美分,20美分,50美分,1美元的硬币,现在有n件商品,每件商品的价格为ai元,问Rikka最少需要携带多少个硬币,使得买每一件商品都不用找零(商品与商品之间互不影响)。如果一定得找零则输出-1。
题解:
如果某件商品的价格膜10不为0,则一定得找零,输出-1.
然后,10美分的硬币最多只会用1个,如果需要2颗10美分的硬币,选取1颗10美分和1颗20美分的硬币会更优。
然后,20美分的硬币最多只会用3个,如果需要4颗20美分的硬币,选取1颗10美分,2颗20美分,1颗50美分的硬币会更优。
然后,50美分的硬币最多只会用1个,如果需要2个50美分的硬币,选取1颗50美分和1颗1美元的硬币会更优。
剩下的用1美元的补充即可。
所以最多拿1颗10美分,3颗20美分,1颗50美分,总共有16种情况,用一个四位数组记录取i个10,j个20,k个50的和,而且和最大为120.
对于所有情况,我们先判断这个值是否大于100,如果大于100,则判断这个值a % 100 + 100(因为10,20,50最大和才100,因此加100)后能不能由前面的10,20,50构成,如果可以,则需要1美元的个数为a / 100 - 1,如果不能,那么需要1美元的个数为a / 100;如果这个值小于100,那么只需判断这个数能否由i个10,j个20,k个50组成即可,最终维护最小值minn。
AC_Code:
#include <bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
bool s[2][4][2][200];// 最多1个10,3个20,1个50,和为120
int a[123];
void init(){
memset(s,false,sizeof(s));
for(int i=0; i<2; ++i)
for(int j=0; j<4; ++j)
for(int k=0; k<2; ++k)
for(int l=0; l<=i; ++l)
for(int m=0; m<=j; ++m)
for(int n=0; n<=k; ++n)
s[i][j][k][10*l+m*20+n*50] = true;
}
int main(){
freopen("in.txt","r",stdin);
init();
int t;
while(~scanf("%d",&t)){
while(t--){
int n;bool flag = false;
scanf("%d",&n);
for(int i=0; i<n; ++i){
scanf("%d",&a[i]);
if(a[i] % 10){
flag = true;
}
}
if(flag){
puts("-1");
continue;
}
int minn = inf;
for(int i=0; i<2; ++i){
for(int j=0; j<4; ++j){
for(int k=0; k<2; ++k){
int sum = 0, ans = 0;
for(int l=0; l<n; ++l){
if(a[l] >= 100 && s[i][j][k][a[l]%100+100]){ // 110 120 210 220 310 320
ans = a[l] / 100 - 1;
}
else if(s[i][j][k][a[l] % 100]){
ans = a[l] / 100;
}
else{
ans = inf;
}
sum = max(sum,ans);
}
minn = min(minn, sum + i + j + k);
}
}
}
cout << minn << endl;
}
}
}