zoukankan      html  css  js  c++  java
  • poj 3040 Allowance

      大致题意:有1到N种硬币,第i种硬币的数量为Bi、价值Vi;Farmer John每周要给他的奶牛发至少价值为C的补贴;问利用前面的N种硬币,最多可以给他的奶牛发多少周的补贴?  这是道贪心的题应该不难察觉出来,下面就说下这里贪心的方法: 既然每周发的钱是至少为C,那么用上述硬币凑出来的价值必须是>=C的; 因为凑出来的价值很可能总是不能刚好等于C的,所以大部分时候给的都是会比C要大一些的,而为了能让john尽可能多的发多几周补贴,那就得让每次发的补贴中"比C多出的那部分"尽可能的小;这样做即等于 能够节约更多些钱 来为后面当补贴发。

      1、将硬币价值从大到小排序。

      2、假设前面k种的硬币价值都是大于等于C的,那么这些就直接取(即一周发一个硬币),因为这些是没办法节约的了。

      3、那么用k+1种到第N种都是硬币价值小于C的了;就从大到小拿 尽可能的多拿,但不能大于C(即假如第i种硬币所有拿走都还小于C,就把第i种全拿走,然后往后同样方式判断第i+1种硬币, 直至最接近C而又小于C )。

      4、如果第3步中拿的价值小于C;那就从第k+1种到第N种硬币中 从小到大拿,也是尽可能的多拿,直到刚好>=C就停止;这样就使得损失为最小了。

      5、将这样取钱方式所能出现的次数 加入到计数器(如果直接一周一周的模拟...可能会超时==...), 然后返回第3步。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #include<cctype>
     7 #include<algorithm>
     8 #include<set>
     9 #include<map>
    10 #include<vector>
    11 #include<queue>
    12 #include<stack>
    13 #include<utility>
    14 #define ll long long
    15 #define inf 0x3f3f3f3f
    16 using namespace std;
    17 
    18 int n,c;
    19 typedef struct node
    20 {
    21     int v,b;
    22 } node;
    23 node a[25];
    24 bool cmp(node a,node b)
    25 {
    26     return a.v>b.v;
    27 }
    28 int cnt;
    29 int main()
    30 {
    31     //freopen("input.txt","r",stdin);
    32     scanf("%d%d",&n,&c);
    33     for(int i=0; i<n; i++)
    34         scanf("%d%d",&a[i].v,&a[i].b);
    35     sort(a,a+n,cmp);  //按价值从大到小排序
    36     //
    37     cnt=0;
    38     int i;
    39     for(i=0;; i++) // 把大于等于c的先全部发完
    40     {
    41         if(a[i].v>=c)
    42             cnt+=a[i].b;
    43         else
    44             break;
    45     }
    46     //经过上面的循环,0到i-1种类的硬币都发完了
    47     int need[25]; //标记某一种硬币用了多少个
    48     while(true)
    49     {
    50         memset(need,0,sizeof(need));
    51         int sum=c;
    52         for(int j=i;j<n;j++)
    53         {
    54             if(a[j].b&&sum>0)
    55             {                //从大到小取,但不能超过c!
    56                 need[j]+=min(a[j].b,sum/a[j].v);
    57                 sum-=a[j].v*need[j];
    58             }
    59         }
    60         //
    61         if(sum>0)
    62         {
    63             int temp;
    64             for(int j=n-1;j>=i;j--)
    65             {
    66                 if(a[j].b&&sum>0) //如果上面那次取法不够,就从小往大找补替,这样保证是最小损失
    67                 {
    68                     temp=min(a[j].b-need[j],(sum+a[j].v-1)/a[j].v);
    69                     if(temp>0)
    70                     {
    71                         sum-=temp*a[j].v;
    72                         need[j]+=temp;
    73                     }
    74                 }
    75             }
    76         }
    77         if(sum>0)
    78             break; //如果还不够,就直接退出了
    79         //
    80         int temp=inf;
    81         for(int j=i;j<n;j++)
    82         {
    83             if(need[j])
    84             {           //这里取最小的  每次需要的种类的次数; 从而避免用c来每周每周的计算(会超时哒=_=)
    85                 temp=min(temp,a[j].b/need[j]);
    86             }
    87         }
    88         cnt+=temp;
    89         for(int j=i;j<n;j++)
    90         {
    91             if(need[j])
    92             {           //把用了的硬币删掉
    93                 a[j].b-=temp*need[j];
    94             }
    95         }
    96     }
    97     printf("%d
    ",cnt);
    98     return 0;
    99 }
  • 相关阅读:
    基于s5pv210的uboot总结
    QQ群笔记
    设计模式----适配器模式
    设计模式----桥接模式
    设计模式----建造者模式
    设计模式----原型模式
    设计模式----单例模式
    设计模式----工厂方法模式
    设计模式----设计原则
    JUnit单元测试--小试牛刀
  • 原文地址:https://www.cnblogs.com/geek1116/p/5672751.html
Copyright © 2011-2022 走看看