1. 程式人生 > >ICPC 2015 Changchun A Too Rich(貪心)

ICPC 2015 Changchun A Too Rich(貪心)

其余 技術分享 ice 需要 icpc 原因 要求 while 預處理

問題 A: Too Rich

時間限制: 1 Sec 內存限制: 128 MB

題目描述

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 p dollars 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.

輸入

The ?rst 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 c i means how many coins/banknotes in denominations of i dollars in your wallet.
1≤T≤20000
0≤p≤109
0≤c i≤100000

輸出

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‘.

樣例輸入

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

樣例輸出

9
-1
36

題意:現在有 1,5,10,20,50,100,200,500,1000,2000面值的錢幣,問你要湊夠p元錢最多需要多少張紙幣,給你p和每個面值紙幣的數量
我的想法:但是WA了,首先,
我會預處理出來到這個紙幣最多能夠構成的錢數,面值一共十種,那麽我就二進制枚舉這一種選還是不選,對於選的,我從後向前跑,對於這一種面值,我盡量少選,一保證前面可以
盡量多選,盡量少選就是最少選一張,最多選給定的數量張,在前面足夠構成的情況下選。最後判斷是否可以,但是WA了,我想應該是20,50,500,那裏的問題,但是還沒有找到反例。
找反例:20元的有4張,50元的有三張,這樣的話去湊120元,按照我的想法,因為前面可以湊夠80元,所以50的我只會選一張,剩下的70前面一定可以,但是事實上並不可以,OK,說服自己很舒服
於是正解:首先我們發現查安生錯誤的原因就是50和500需要多少張,為什麽這兩者特殊呢,因為對於別的數字,前面所有的數字都是這個數字的因子,唯獨這兩個數字前面的數字含有非因子,因此,對於每一個
數字,在我們找到最少選多少個之後,對於50,500,還要考慮要不要多選一張,其余的就不需要了。試著寫一下
最原始想法代碼:
技術分享圖片
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
 
using namespace std;
 
int t;
int num;
int tmp;
int a[13];
int c[13];
int sum[13];
int zhao[13] = {1,5,10,20,50,100,200,500,1000,2000};
int ans;
int l;
int fac[13];
 
void init()
{
    fac[0] = 1;
    for(int i=1; i<=10; i++)
        fac[i] = fac[i-1]*2;
}
 
int main()
{
    init();
    scanf("%d", &t);
    while( t-- )
    {
        scanf("%d", &num);
        ans = -1;
        for(int i=0; i<10; i++)
        {
            scanf("%d", &a[i]);
            if(i == 0) sum[i] = a[i]*zhao[i];
            else sum[i] = sum[i-1]+a[i]*zhao[i];
            if(sum[i] <= num)
                l = i+1;
        }
        for(int i=fac[l]-3; i<=1023; i++)
        {
            int ttmp = i;
            tmp = num;
            int res = 0;
            for(int j=9; j>=0; j--)
            {
                if(!(ttmp>>j)&1) continue;
                if(zhao[j] > tmp)
                {
                    res = -1;
                    break;
                }
                int wu = tmp-sum[j-1];
                int liu = max(1, (int)ceil(1.0*wu/zhao[j]));
                liu = min(liu, a[j]);
                res += liu;
                tmp -= liu*zhao[j];
            }
            if(tmp != 0)
            {
                res = -1;
            }
            if(res != -1)
            {
                 ans = res;
                 break;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}
View Code
錯一發代碼:
技術分享圖片
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>

using namespace std;

const int maxn = 13;

int t;
int num;
int a[maxn];
int f[10] = {1,5,10,20,50,100,200,500,1000,2000};
int sum[13];
int ans;

void init()
{
    ans = -1;
}

void input()
{
    scanf("%d" , &num);
    for(int i=0; i<10; i++)
    {
        scanf("%d" , &a[i]);
        if(i == 0)
            sum[i] = a[i]*f[i];
        else
            sum[i] = sum[i-1]+a[i]*f[i];
//        printf("%d..%d..\n" , i , sum[i]);
    }
}

void solve(int id, int rem , int res)
{
//    printf("%d..%d..%d..\n" , id , rem , res);
    if(id < 0)
    {
        if(rem == 0)
        {
            ans = max(ans , res);
        }
        return ;
    }
    int tmp = rem-sum[id-1];
    int ttmp = max(0,(int)ceil(1.00*tmp/f[id]));
    ttmp = min(ttmp , a[id]);   ///算出來選擇多少張
    solve(id-1 , rem-f[id]*ttmp , res+ttmp);
    if(f[id]==50 || f[id]==500)
    {
        ttmp++;
        if(ttmp <= a[id])
        solve(id-1 , rem-f[id]*ttmp , res+ttmp);
    }
}

int main()
{
    scanf("%d" , &t);
    while( t-- )
    {
        init();
        input();
        solve(9,num,0);
        printf("%d\n" , ans);
    }

    return 0;
}
View Code

看題解上寫的是轉換成盡可能多的去掉大面值的,使得剩下的可以構成要求的數字,對於50與500,另外考慮下少去掉一張,與我寫的盡可能少選擇大面值的,多選擇一張有什麽不同之處嗎

代碼是沒有什麽問題的 應該是邏輯上的問題

先改成去掉寫一下試試

為什麽就過了呢 這個問題暫時挖坑

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>

using namespace std;

const int maxn = 13;
const int inf = 10000000;

int t;
int num;
int a[maxn];
int f[10] = {1,5,10,20,50,100,200,500,1000,2000};
int sum[13];
int ans;
int all;

void init()
{
    all = 0;
    ans = 10000000;
}

void input()
{
    scanf("%d" , &num);
    for(int i=0; i<10; i++)
    {
        scanf("%d" , &a[i]);
        all += a[i];
        if(i == 0)
            sum[i] = a[i]*f[i];
        else
            sum[i] = sum[i-1]+a[i]*f[i];
    }
}

void solve(int id, int rem , int res)
{
    if(id < 0)
    {
        if(rem == 0)
        {
            ans = min(ans , res);
        }
        return ;
    }
    int tmp = a[id];
    tmp = min(tmp , rem/f[id]);
    tmp = max(0 , tmp);
    solve(id-1 , rem-tmp*f[id] , res+tmp);
    if(tmp)
    {
        tmp--;
        solve(id-1 , rem-tmp*f[id] , res+tmp);
    }
}

int main()
{
    scanf("%d" , &t);
    while( t-- )
    {
        init();
        input();
        solve(9,sum[9]-num,0);
//        printf("%d...\n" , ans);
        if(ans == 10000000)
            printf("-1\n");
        else
            printf("%d\n" , all-ans);
    }

    return 0;
}



ICPC 2015 Changchun A Too Rich(貪心)