Too Rich HDU - 5527 (贪心+思维)

这道题看起来比较像经典的货币问题,贪心可解。其实仔细观察的会发现20-50, 200-500之间不存在倍数关系,所以没有办法直观的用贪心来解。假如在某个例子中  只剩下了一张50 三张20  此时差为60,按照贪心算法的话  你会直接拿50  还剩的10你就拿不出来了

我们这时去凑出来倍数就好了,比如放两个50就等于放一个100,也就符合了倍数关系。

注意分类讨论。

//too rich
#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;

typedef struct money{
    int c; //面值
    int n; //数量
}Money;
Money m[10];

typedef long long ll;
ll sum1, sum2, dif, p; //总张数,总金额,差值
int cont, T;//答案,最优张数
//返回答案,若找不到返回-1
int solve(int dif)
{
    int ans = 0;
    for(int i = 10; i >= 1; i--){
        if(p == 0) break;
        if(m[i].n <= 0) continue;
        //当面额为50或500时,试试两个两个放,再试试一个一个放
        if(m[i].c==50 || m[i].c==500){
            //默认为两个两个放
            if(m[i].n >= 2){
                //核心算法,较难理解
                int tn = m[i].n/2;
                int t1 = min(dif, m[i].c*tn*2);
                int t2 = t1/(m[i].c*2);
                dif -= t2*m[i].c*2;
                ans += t2*2;
            }

        }else{
            //面额不为50,500时
            int t1 = min(dif, m[i].c*m[i].n);
            int t2 = t1/m[i].c;
            dif -= t2*m[i].c;
            ans += t2;
        }
    }
    if(dif == 0) return ans;
    return -1;
}

int main()
{
    m[1].c = 1;m[2].c = 5;m[3].c = 10;m[4].c = 20;m[5].c = 50;
    m[6].c = 100;m[7].c = 200;m[8].c = 500;m[9].c = 1000;m[10].c = 2000;
    scanf("%d",&T);
    while(T--){
        sum1 = 0, sum2 = 0, cont = 1e9;
        scanf("%lld",&p);
        for(int i = 1; i <= 10; i++){
            scanf("%d",&m[i].n);
            sum1 += m[i].n;
            sum2 += (m[i].c * m[i].n);
        }
        dif = sum2 - p; //差
        if(dif < 0){
            printf("-1\n");
            continue;
        }
        //情况1:50,500都用偶数张
        int ans = solve(dif);
        if(ans != -1) cont = min(ans, cont);
        //情况2:50用奇数张
        if(dif>=50 && m[5].n>0){
            m[5].n--;
            int ans = solve(dif-50);
            m[5].n++; //回溯
            if(ans != -1) cont = min(ans+1, cont);
        }
        //情况3:500用奇数张
        if(dif>=500 && m[8].n>0){
            m[8].n--;
            int ans = solve(dif-500);
            m[8].n++; //回溯
            if(ans != -1) cont = min(ans+1, cont);
        }
        //情况4:50,500都用奇数张
        if(dif>=550 && m[5].n>0 && m[8].n>0){
            m[5].n--; m[8].n--;
            int ans = solve(dif-550);
            m[5].n++; m[8].n++;//回溯
            if(ans != -1) cont = min(ans+2, cont);
        }

        if(cont == -1) printf("-1\n");
        else printf("%lld\n",sum1-cont);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/a1097304791/article/details/82226447