poj 3040 Allowance (贪心

     作为创纪录的牛奶生产的奖励,农场主约翰决定开始给Bessie奶牛一个小的每周津贴。FJ有一套硬币N种(1≤N≤20)不同的面额,每枚硬币是所有比他小的硬币面值的倍数,例如1美分硬币、5美分硬币、10美分硬币和50美分硬币。使用这些硬币,FJ每周至少给Bessie C(1 <= C <=100000000)美分。请你计算他最多能给Bessie几周 
Input
    * 第一行N 、 C

    * 第 2..N+1行: 硬币价值 V (1 <= V <= 100,000,000) 和数量 B (1 <= B <= 1,000,000) 
Output
    * 使用这些硬币,每周至少给C美分的前提下的最多周数 
Sample Input

    3 6
    10 1
    1 100
    5 120

Sample Output

    111

此题贪心情况有三个:

1. 对于硬币面值大于c的,贪心情况是不搭配别的一次只发一个损失最小,先把这些发完

2. 对于可以凑成c的硬币搭配,参与组合的硬币面值越大,所用的硬币越少,剩下的硬币搭配的可能性更多,先把这些发完

3. 对于1.2情况处理后,用处理2的思路找出最接近c的硬币搭配,再从小到大找最后一枚硬币(已用2的思路贪心处理过了,结果已尽可能接近c而不到c,最后一枚参与的硬币越小,损失约越小)

 

注意2.3贪心情况的实现,凑c的循环可共同利用

#include<cstdio>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
struct node{
     int x,n;
     int m,mn;
     bool operator < (const node &rsh) const{
         return x<rsh.x;
     }
}a[30];
int main(){
     int n,c,ans=0;
     scanf("%d%d",&n,&c);
     for(int i=0 ; i<n ; i++)scanf("%d%d",&a[i].x,&a[i].n),a[i].m=0;
     sort(a,a+n);

         for(int i=n-1 ; i>=0 ; i--){                     //大于c的硬币
             if(a[i].x>=c&&a[i].n>0)
                ans+=a[i].n,a[i].n=0;
         }
         int flag=1;
     while(flag){

            int mm=c,mn=inf;
            for(int i=n-1 ; i>=0 ; i--){                 //从大到小尽力填充
                    a[i].m=0;
                if(a[i].n){
                    a[i].m=min(a[i].n,mm/a[i].x);
                    mm-=a[i].m*a[i].x;
                }
                if(mm==0)break;
            }
            if(mm>0){                                             //填充不了正好c,但此时就算是最小的硬币也尽力填充了,决定是否大于c的只是最后的  一 枚硬币
                 for(int i=0 ; i<n ; i++){                  //用面值最小的硬笔开始填充,损失最小的贪心选择
                     if(a[i].x>mm&&(a[i].n-a[i].m)){
                         a[i].m++;
                         mm-=a[i].x;
                         break;
                     }
                 }
            }
            if(mm>0)break;
            for(int i=0 ; i<n ; i++)if(a[i].m)mn=min(mn,a[i].n/a[i].m);
            ans+=mn;
            for(int i=0 ; i<n ; i++)if(a[i].m)a[i].n-=mn*a[i].m;
         }
     //for(int i=0 ; i<n ; i++)printf("%d %d\n",a[i].x,a[i].n);
    printf("%d",ans);
     return 0;
}
posted @ 2019-03-14 00:22  易如鱼  阅读(254)  评论(0编辑  收藏  举报