NKOJ 1243 【USACO OCT09】零用钱
NKOJ 1243 【USACO OCT09】零用钱
思路
-
读题:题目中有一句话值得注意
每一个面额都能整除所有比它大的面额。
通过这句话实际上可以知道,所有小面额都可以凑出大面额。
-
对初步想法的延伸:既然小面额能凑出大面额,当我有的钱数不足以发刚好 \(c\) 元时,浪费大面额一定比浪费小面额划算,如:我要发六块,我有一张十块和两张五块,两张一块,我在有十块的情况下一定不会发两张五块,因为五块的可以和一块的凑。
-
既然如此我们不妨模拟每一次发钱。
- 先尝试凑正好 \(c\) 元,如果当前面额在不超过 \(c\) 的情况下能凑就拿,不然就下一个面额接着拿。
- 如果不能刚好凑够 \(c\) 元,就从小面额开始找正好超过一点点的面额,如果找不到,就说明钱全部被拿完了,只能退出。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
int n,c,ans=0;
struct node{int v,num;}arr[25];
bool cmp(node x,node y){return x.v>y.v;}
int main(){
scanf("%d%d",&n,&c);
for(int i=1;i<=n;i++) scanf("%d%d",&arr[i].v,&arr[i].num);
sort(arr+1,arr+1+n,cmp);
while(1){
int now=c;
for(int i=1;i<=n;i++){
while(arr[i].v<=now&&arr[i].num>0) now-=arr[i].v,arr[i].num--;
}
if(now>0){
for(int i=n;i>=1;i--){
if(arr[i].v>=now&&arr[i].num>0){
now-=arr[i].v,arr[i].num--;
break;
}
}
}
if(now>0) break;
ans++;
}
printf("%d",ans);
return 0;
}