POJ 1787 Charlie's Change (多重背包 带结果组成)

本文介绍了一个多重背包问题的解决方法,使用C++实现了一个具体的例子。该算法通过优化选择不同面额硬币的数量来达到所需的总金额,并记录了最优解中各面额硬币的选择数量。

题意:求通过c1个1分的c2个5分的c3个10分的c4个25分的组成p的最多个数并且输出分别选多少个。

分析:多重背包+一个数组保存当前最优解情况下选的个数;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
#include <cstdlib>
#include <map>
#include <vector>

using namespace std;

const int oo = 1e8;

struct C
{
    int x, num;
}c[120];

void Init(int c1, int x, int &k)
{
    int num = 1;
    while(c1>=num)
    {
        c[k].x = num*x;
        c[k++].num = num;
        c1-=num;
        num*=2;
    }
    if(c1!=0)
    {
        c[k].x = c1*x;
        c[k++].num = c1;
    }
}

bool cmp(C x1, C x2)
{
    return x1.x < x2.x;
}
int dp[10005];
int ans[10005][6];

int main()
{
    int p, c1, c2, c3, c4;
    while(scanf("%d %d %d %d %d", &p, &c1, &c2, &c3, &c4), p+c1+c2+c3+c4)
    {
        int k = 0;
        Init(c1, 1, k);
        Init(c2, 5, k);
        Init(c3, 10, k);
        Init(c4, 25, k);
        sort(c, c+k, cmp);
        memset(dp, 0, sizeof(dp));
        memset(ans, 0, sizeof(ans));
        dp[0] = 1;
        for(int i=0; i<k; i++)
        {
            for(int j=p; j>=c[i].x; j--)
            {
                if(dp[j-c[i].x]&&dp[j-c[i].x]+c[i].num > dp[j])
                {
                    dp[j] = dp[j-c[i].x]+c[i].num;
                    int x = c[i].x/c[i].num;
                    if(x==1)
                    {
                        ans[j][1] = ans[j-c[i].x][1]+c[i].num;
                        ans[j][2] = ans[j-c[i].x][2];
                        ans[j][3] = ans[j-c[i].x][3];
                        ans[j][4] = ans[j-c[i].x][4];
                    }
                    else if(x==5)
                    {
                        ans[j][2] = ans[j-c[i].x][2]+c[i].num;
                        ans[j][1] = ans[j-c[i].x][1];
                        ans[j][3] = ans[j-c[i].x][3];
                        ans[j][4] = ans[j-c[i].x][4];
                    }
                    else if(x==10)
                    {
                        ans[j][3] = ans[j-c[i].x][3]+c[i].num;
                        ans[j][2] = ans[j-c[i].x][2];
                        ans[j][1] = ans[j-c[i].x][1];
                        ans[j][4] = ans[j-c[i].x][4];
                    }
                    else
                    {
                        ans[j][4] = ans[j-c[i].x][4]+c[i].num;
                        ans[j][2] = ans[j-c[i].x][2];
                        ans[j][3] = ans[j-c[i].x][3];
                        ans[j][1] = ans[j-c[i].x][1];
                    }
                }
            }
        }
        if(dp[p]==0)
            printf("Charlie cannot buy coffee.\n");
        else
            printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",
                   ans[p][1], ans[p][2], ans[p][3], ans[p][4]);
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/mengzhong/p/5517576.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值