poj3040 Allowance 题解报告

题目传送门

【题目大意】

有$n$种面值的硬币,第$i$种有$b_i$个,大的硬币是小的硬币的倍数,给定一个金额$k$,求最多可以组成多少份金额不小于$k$的组合。

【思路分析】

首先去掉能自成一组的硬币,然后考虑几种硬币凑成一组,贪心策略就是优先考虑面值大的,细节见代码。

【代码实现】

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define g() getchar()
 7 #define rg register
 8 #define go(i,a,b) for(rg int i=a;i<=b;i++)
 9 #define back(i,a,b) for(rg int i=a;i>=b;i--)
10 #define db double
11 #define ll long long
12 #define il inline
13 #define pf printf
14 #define mem(a,b) memset(a,b,sizeof(a))
15 using namespace std;
16 ll fr(){
17     ll w=0,q=1;
18     char ch=g();
19     while(ch<'0'||ch>'9'){
20         if(ch=='-') q=-1;
21         ch=g();
22     }
23     while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g();
24     return w*q;
25 }
26 const int N=22;
27 ll n,c,ans,use[N];
28 struct money{
29     ll v,b;
30 }coin[N];
31 bool tag;
32 bool cmp(money A,money B){
33     return A.v<B.v;
34 }
35 int main(){
36     //freopen("","r",stdin);
37     //freopen("","w",stdout);
38     n=fr();c=fr();
39     go(i,1,n) coin[i].v=fr(),coin[i].b=fr();
40     sort(coin+1,coin+1+n,cmp);
41     back(i,n,1){//先把可以单独一组的去掉
42         if(coin[i].v<c) break;
43         ans+=coin[i].b;
44         coin[i].b=0;
45     }
46     while(1){
47         mem(use,0);
48         tag=0;
49         rg ll t=c,m;//t记录当前组成一组还需要的钱数
50         back(i,n,1){
51             if(coin[i].b){
52                 rg ll num=t/coin[i].v;
53                 m=min(num,coin[i].b);
54                 t-=m*coin[i].v;
55                 use[i]=m;//记录使用了多少个此面值的硬币
56                 if(t==0) {tag=1;break;}//如果组成一组了就退出
57             }
58         }
59         if(t>0){//无法凑整的情况
60             go(i,1,n){
61                 if(coin[i].b>use[i]){//用有剩余的硬币来补
62                     while(use[i]<coin[i].b){
63                         if(t<0) {tag=1;break;}
64                     }
65                 }
66                 if(tag) break;
67             }
68         }
69         if(!tag) break;//无法凑成一组的情况
70         rg ll as=1e9+7;
71         go(i,1,n) if(use[i]) as=min(as,coin[i].b/use[i]);
72 //考虑到有几种硬币凑成一组的情况所以要取最小值
73         ans+=as;
74         go(i,1,n) coin[i].b-=use[i]*as;
75     }
76     pf("%lld\n",ans);
77     return 0;
78 }
代码戳这里
posted @ 2019-08-21 09:41  小叽居biubiu  阅读(193)  评论(0编辑  收藏  举报