zoukankan      html  css  js  c++  java
  • HDU 5527 贪心

    Too Rich

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
    Total Submission(s): 1666    Accepted Submission(s): 422

    Problem Description
    You are a rich person, and you think your wallet is too heavy and full now. So you want to give me some money by buying a lovely pusheen sticker which costs pdollars from me. To make your wallet lighter, you decide to pay exactly p dollars by as many coins and/or banknotes as possible.

    For example, if p=17 and you have two $10 coins, four $5 coins, and eight $1 coins, you will pay it by two $5 coins and seven $1 coins. But this task is incredibly hard since you are too rich and the sticker is too expensive and pusheen is too lovely, please write a program to calculate the best solution.
     
    Input
    The first line contains an integer T indicating the total number of test cases. Each test case is a line with 11 integers p,c1,c5,c10,c20,c50,c100,c200,c500,c1000,c2000, specifying the price of the pusheen sticker, and the number of coins and banknotes in each denomination. The number ci means how many coins/banknotes in denominations of i dollars in your wallet.

    1T20000
    0p109
    0ci100000
     
    Output
    For each test case, please output the maximum number of coins and/or banknotes he can pay for exactly p dollars in a line. If you cannot pay for exactly p dollars, please simply output '-1'.
     
    Sample Input
    3 17 8 4 2 0 0 0 0 0 0 0 100 99 0 0 0 0 0 0 0 0 0 2015 9 8 7 6 5 4 3 2 1 0
     
    Sample Output
    9 -1 36
     
    Source
     
    听说是一个金牌题,确实很巧妙。
    开始的想法是,多重背包,用二进制优化成01背包,d[i] :钱币为 i 的最多钱币数目,但是开不了这么大的数组,用map映射一下,或者改成记忆化搜索写法,但是是不可能的,记忆化还是得有一个vis数组~~~。
     
     
    正解:
    先转换思路,凑P求最多硬币,转为求mon - P 的最少硬币数。
    然后贪心,但是会像记忆化搜索一样要回溯。直接贪心不太好。但是,硬币问题有一个特点,如果所有的钱币如: 1  ,   5   ,   10  ,   20  , 40   ,   80  ,   800,你已经看出来了,就是这种前面是后面的因子,这样就不可能说要从后往前的过程中要回溯。直接从后往前贪心。
     
    怎么转为这种情况呢,发现只要改变两个数  50,500,改成 100,1000来用,就可以了。
    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int inf = 0x3f3f3f3f;
    
    int c[30];
    int v[10] = {1,5,10,20,50,100,200,500,1000,2000};
    int num[10];
    int sum,mon,p,ans;
    
    int solve(int x) {
        int ret = 0,need;
    
        for(int i = 9; i >=0; i--) {
    
            if(v[i]==500) {
                need = x/1000;
                need = min(need,num[i]/2);
                ret +=2*need;
                x-=need*1000;
            }
            else if(v[i]==50) {
                need = x/100;
                need = min(need,num[i]/2);
                ret +=2*need;
                x-=need*100;
            }
            else {
                need = x/v[i];
                need = min(need,num[i]);
                ret +=need;
                x -=need*v[i];
            }
        }
        if(x) return inf;
        return ret;
    
    }
    
    int main()
    {
        //freopen("in.txt","r",stdin);
        int T;
        scanf("%d",&T);
        while(T--) {
    
            sum = mon = 0;
            scanf("%d",&p);
            for(int i = 0; i < 10; i++) {
                scanf("%d",&num[i]);
                sum +=num[i];
                mon +=num[i]*v[i];
            }
    
            p = mon - p;    //最少的硬币去兑换
    
            if(p<0) {
                puts("-1");
                continue;
            }
    
            ans = inf;
            ans = min(ans,solve(p));
    
    
            if(num[7]) {
                p-=500;num[7]--;
                if(p>=0)
                    ans = min(ans,solve(p)+1);
                p+=500;num[7]++;
            }
            if(num[4]) {
                p-=50;num[4]--;
                if(p>=0)
                    ans = min(ans,solve(p)+1);
                p+=50;
                num[4]++;
            }
            if(num[4]&&num[7]) {
                p-=550;num[4]--;num[7]--;
                if(p>=0)
                    ans = min(ans,solve(p)+2);
            }
            if(ans==inf) puts("-1");
            else printf("%d
    ",sum-ans);
        }
    
    
    
        return 0;
    }
    View Code
     
  • 相关阅读:
    [Hyper-V]使用操作系统模板创建新的虚拟机
    [Hyper-V]给Hyper-V创建两块网卡备用
    [Hyper-V]在Windows 8.1 操作系统中启用Hyper-V功能
    [MSSQL]SCOPE_IDENTITY,IDENT_CURRENT以及@@IDENTITY的区别
    [Microsoft Test Manager]CodeUI初探
    [MSSQL] Useful SQL Scripts
    Run Android on Your Netbook or Desktop
    How Delete File with Readonly Permission?
    Getting the first day in a week with T-SQL
    [HtmlUnit]Fetch Dynamic Html/Content Created By Javascript/Ajax
  • 原文地址:https://www.cnblogs.com/TreeDream/p/7861776.html
Copyright © 2011-2022 走看看