POJ 3040 贪心寻找组合

题目

Allowance
Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 2611   Accepted: 1069

Description

As a reward for record milk production, Farmer John has decided to start paying Bessie the cow a small weekly allowance. FJ has a set of coins in N (1 <= N <= 20) different denominations, where each denomination of coin evenly divides the next-larger denomination (e.g., 1 cent coins, 5 cent coins, 10 cent coins, and 50 cent coins).Using the given set of coins, he would like to pay Bessie at least some given amount of money C (1 <= C <= 100,000,000) every week.Please help him ompute the maximum number of weeks he can pay Bessie.

Input

* Line 1: Two space-separated integers: N and C 

* Lines 2..N+1: Each line corresponds to a denomination of coin and contains two integers: the value V (1 <= V <= 100,000,000) of the denomination, and the number of coins B (1 <= B <= 1,000,000) of this denomation in Farmer John's possession.

Output

* Line 1: A single integer that is the number of weeks Farmer John can pay Bessie at least C allowance

Sample Input

3 6
10 1
1 100
5 120

Sample Output

111

Hint

INPUT DETAILS: 
FJ would like to pay Bessie 6 cents per week. He has 100 1-cent coins,120 5-cent coins, and 1 10-cent coin. 

OUTPUT DETAILS: 
FJ can overpay Bessie with the one 10-cent coin for 1 week, then pay Bessie two 5-cent coins for 10 weeks and then pay Bessie one 1-cent coin and one 5-cent coin for 100 weeks.

想法

之前为了这道题看了好多的解题报告,然而大部分代码都是一样的,而且解题过程写的也不是特别容易理解= =... 作为初学者的我看了一天多都没明白。其实仔细想想也是很容易理解的。

首先,大于等于C的直接支付一天,无需考虑。

对于小于C的情况,先选择大的货币,但是不超出C,如果正好(left=0)那就直接计算最大支付天数(canpayday)然后按照比例减去货币。

如果没凑齐,(left>0)那么从面值小的向大的方向凑齐,这个过程中如果凑齐了那就计算canpayday,按比例减去.

如果还没凑齐,那基本上就是没有货币了。break掉。

大概思路就是这样,下面贴代码

View Source On GitHub

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <vector>
#include <algorithm>
using namespace std;

struct cash
{
    int value;
    int amount;
};

bool cmp(const cash& a,const cash& b)
{
    return a.value<b.value;
}

int need[64];
int makedayfrom(vector<cash>& vec,int C)
{
    memset(need,0,sizeof(int)*64);
    int N=vec.size();
    int left=C;
    for(int i=N-1;i>=0;i--)
    {//
        if(vec.at(i).amount>0&&left>0)
        {
            int x=left/vec.at(i).value;
            x=min(x,vec.at(i).amount);
            need[i]=x;
            left-=x*vec.at(i).value;
        }
    }
    if(left>0)
    {
        for(int i=0;i<N;i++)
        {
            if(vec.at(i).amount>need[i]&&left>0)
            {
                int x=left/vec.at(i).value;
                if(x==0)
                {
                    /// try to make x = 1
                    need[i]++;
                    left=0;
                    break;
                }
            }
        }
    }
    if(left>0)
    {
        return -1;
    }
    int canpayday=2<<29;
    for(int i=0;i<64;i++)
    {
        if(need[i]>0)
        {
            canpayday=min(canpayday,vec.at(i).amount/need[i]);
        }
    }
    if(canpayday<=0) return -1;
    for(int i=0;i<N;i++)
    {
        if(need[i]>0)
        {
            vec.at(i).amount-=canpayday*need[i];
        }
    }
    return canpayday;

}
int main()
{
    int N,C;
    scanf("%d %d",&N,&C);
    vector<cash> vec;
    int ans=0;
    for(int i=0;i<N;i++)
    {
        cash s;
        scanf("%d %d",&s.value,&s.amount);
        vec.push_back(s);
    }
    sort(vec.begin(),vec.end(),cmp);
    for(int i=N-1;i>=0;i--)
    {
        if(vec.at(i).value>=C)
        {
            ans+=vec.at(i).amount;
            vec.pop_back();
        }
        else break;
    }
    int tmp;
    while((tmp=makedayfrom(vec,C))>0)
    {
        ans+=tmp;
    }
    printf("%d\n",ans);
    return 0;
}
中间还参考了一些别的代码,直接上链接:

View Source On GitHub

View Source On GitHub

View Source On GitHub



我在GitHub上建立了一个仓库,用于存放已经AC的题目的源代码。如果各位有未收录的题目或者有更好的解法,欢迎fork仓库+PR~ 让我们共同创建一个AC代码集中仓库,造福ACM Beginner ~

仓库地址: OJ-Problems-Source On GitHub


你可能感兴趣的:(poj,贪心)