九度OJ 1433 FatMouse(贪心)

原题地址:http://ac.jobdu.com/problem.php?pid=1433

题目描述:

FatMouse prepared M pounds of cat food, ready to trade with the cats guarding the warehouse containing his favorite food, JavaBean.
The warehouse has N rooms. The i-th room contains J[i] pounds of JavaBeans and requires F[i] pounds of cat food. FatMouse does not have to trade for all the JavaBeans in the room, instead, he may get J[i]* a% pounds of JavaBeans if he pays F[i]* a% pounds of cat food. Here a is a real number. Now he is assigning this homework to you: tell him the maximum amount of JavaBeans he can obtain. 

输入:

The input consists of multiple test cases. Each test case begins with a line containing two non-negative integers M and N. Then N lines follow, each contains two non-negative integers J[i] and F[i] respectively. The last test case is followed by two -1's. All integers are not greater than 1000.

输出:

For each test case, print in a single line a real number accurate up to 3 decimal places, which is the maximum amount of JavaBeans that FatMouse can obtain.

样例输入:
5 3
7 2
4 3
5 2
20 3
25 18
24 15
15 10
-1 -1
样例输出:
13.333
31.500

本题是贪心算法相对简单的应用,“贪心”与其说是一种算法倒不如说是一种思想,即一种总是选择“当前最好的选择”而不从整体上去把握的思想

题目大意如下:有m元钱,n种物品,每种物品有J[i]磅,每种物品的总价值为F[i],可以用0~F[i]间的任意价格买到相应磅数的物品,如0.3*F[i]元可以买到0.3*J[i]磅物品。求m元最多能买到多少重量的物品

由于每次不需要完全购买某个物品,所以假设F[i]和F[j]相同,如果J[i]>J[j],肯定是先把钱花在物品i上,因此得出了贪心的策略:每次都买剩余物品中性价比(这里是磅/元)最高的物品,直到该物品被买完或者钱耗尽了,若物品i被买完了,再去买剩余中性价比最高的物品,重复该过程直到m元耗尽。

该贪心策略能得到最优解的简单证明(反证法)如下:

要证明“在最优解中,如果存在性价比为a的物品,那么性价比高于a的物品一定都被买断”,假设该解不是最优解,即存在性价比为b>a的物品还有剩余,而我们获得了所谓的最优解。此时如果我们退掉一点点物品a,把这部分钱用来买b,那么总重量一定比所谓的最优解有所增加,因此所谓的最优解不是最优解,假设不成立。说明该贪心策略是正确的。

可惜,正确的贪心策略并不是每次都显而易见。难过

AC代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define MAXN 1001
using namespace std;

struct warehouse
{
    int J, F; //付出F能购买到J磅
    double performance; //即J/F,每单位金钱能买到的磅数
    bool operator < (const warehouse & A) const
    {
        return performance > A.performance; //重载小于,性价比高的在前
    }
}w[MAXN];

int main()
{
    int M, N;
    while (cin >> M >> N)
    {
        double total = 0;
        if (M == -1 && N == -1)
            break;
        for (int i=0; i<N; ++i)
        {
            cin >> w[i].J >> w[i].F;
            w[i].performance = (double)w[i].J/w[i].F;
        }
        sort(w, w+N);
        for (int index = 0; index<N; ++index)
        {
            if (M > w[index].F)
            {
                total += w[index].J; //完全买下
                M -= w[index].F;
            }
            else if (M>0) //不能全部买下但是还有钱,一定是最后的选择
            {
                total += M*w[index].performance; //按照该性价比买完
                break;
            }
        }
        printf("%.3f\n", total);
    }
    return 0;
}

内存占用:1536Kb 耗时:10ms

算法复杂度:O(nlogn)


九度OJ上类似的题目还有:

1434——时间安排问题,另起一篇

1435——药水浓度问题

1436——拆材料补墙问题

posted @ 2017-03-25 21:25  Lecholin  阅读(152)  评论(0编辑  收藏  举报