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

    http://poj.org/problem?id=3040

    这道题 没有思路欧

    直接网上找到的证明

    贪心,从大到小排序,只要不超额就能放多少就放多少,最后再从小的开始找一个放进去能超额的。

    正确性证明,因为大的是小的倍数,所以大的放进去不超额一定要放进去,因为小的不管怎么取,
    再超过c之前一定会凑成这个大的面额,那么用大的代替一定更优。

    第一步做完之后,那么现在一定要再放进去一个硬币,那么选择最小的并且能大于c的也一定是最优的。

      1 #include <iostream>
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <fstream>
      5 #include <math.h>
      6 #include <algorithm>
      7 
      8 #define INF 111111111
      9 using namespace std;
     10 
     11 typedef long long ll;
     12 typedef pair<ll,ll> P;
     13 
     14 P p[28];
     15 ll cnt[28];
     16 ll n, c, week = 0;
     17 
     18 bool cmp(P p1, P p2)
     19 {
     20     return p1.first > p2.first;
     21 }
     22 
     23 ll getWeek()
     24 {
     25     ll min_num = 0x3f3f3f3f;
     26     for (int i = 0; i < n; i++)
     27     {
     28         if (cnt[i] != 0)
     29         {
     30             min_num = min(min_num, p[i].second / cnt[i]);
     31         }
     32     }
     33     for (int i = 0; i < n; i++)
     34     {
     35         if (cnt[i] != 0)
     36         {
     37             p[i].second -= min_num*cnt[i];
     38         }
     39     }
     40     return min_num;
     41 }
     42 
     43 int main()
     44 {
     45     ifstream cin("in.txt");
     46     freopen("in.txt","r", stdin);
     47     scanf("%d%d", &n, &c);
     48     for (int i = 0; i < n; i++)
     49     {
     50         scanf("%d%d", &p[i].first, &p[i].second);
     51     }
     52     sort(p, p+n, cmp);
     53     //不可节约型的发完
     54     for (int i = 0; i < n; i++)
     55     {
     56         if (p[i].first < c) break;
     57         week += p[i].second;
     58         p[i].second = 0;
     59     }
     60     //从大往小取 取到恰好小于 c
     61     while(1)
     62     {
     63         ll sum = c;
     64         memset(cnt, 0, sizeof(cnt));
     65         //从大开始取
     66         for (int i = 0; i < n; i++)
     67         {
     68             ll num = 0;
     69             if (p[i].second)
     70             {
     71                 num = min(p[i].second,sum / p[i].first);
     72                 sum -= num*p[i].first;
     73                 cnt[i] = num;
     74             }
     75         }
     76         if (sum > 0)
     77         {
     78             //从小开始取
     79             for (int i = n-1; i >= 0; i--)
     80             {
     81                 ll num;
     82                 if (p[i].second > cnt[i])//之前超时的Bug应该是 只判断p[i].second 而没有注意p[i].second其实一直没有变化 在最后算week时才改变
     83                 while(p[i].second > cnt[i])
     84                 {
     85                     sum -= p[i].first;
     86                     cnt[i]++;
     87                     if (sum <= 0) break;
     88                 }
     89                 if (sum <= 0)
     90                 {
     91                     break;
     92                 }
     93             }
     94         }
     95         if (sum > 0) break;
     96         week += getWeek();
     97         //更简洁的写法 代替get_week
     98 //        ll mx = INF;
     99 //        for (int i = n-1; i >= 0; i--)
    100 //        {
    101 //            if (cnt[i])
    102 //            mx = min(mx, p[i].second / cnt[i]);// p[i].second / cnt[i]代表的就是可以给几个星期
    103 //        }
    104 //        for (int i = n-1; i >= 0; i--)
    105 //        {
    106 //            p[i].second -= mx*cnt[i];
    107 //        }
    108     }
    109     printf("%lld
    ",week);
    110     return 0;
    111 }
  • 相关阅读:
    android之wifi开发
    android wifi讲解 wifi列表显示
    jQuery格式化时间插件formatDate
    Android自定义照相机实现(拍照、保存到SD卡,利用Bundle在Acitivity交换数据)
    Android圆形图片自定义控件
    Android自定义控件
    SQL表连接查询(inner join、full join、left join、right join)
    Jquery 中each循环嵌套的使用示例教程
    JQuery遍历json数组的3种方法
    怎样从数据库层面检測两表内容的一致性
  • 原文地址:https://www.cnblogs.com/oscar-cnblogs/p/6360258.html
Copyright © 2011-2022 走看看