zoukankan      html  css  js  c++  java
  • 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
    ",ans);
    77     return 0;
    78 }
    代码戳这里
  • 相关阅读:
    14_部署LNMP环境、构建LNMP平台、地址重写
    13_搭建Nginx服务器、配置网页认证、基于域名的虚拟主机、ssl虚拟主机
    12_rsync+SSH同步
    11_DNS子域授权、分离解析、缓存DNS服务器
    10_自定义yum仓库、源码编译安装
    09_parted分区工具、交换分区、链路聚合
    08_简单MariaDB数据库的管理
    bzoj1396
    bzoj4154
    bzoj3489
  • 原文地址:https://www.cnblogs.com/THWZF/p/11386945.html
Copyright © 2011-2022 走看看