poj1787 Charlie's Change(多重背包+路径)


http://poj.org/problem?id=1787

题意:查理想买咖啡,咖啡销售机只支持三种硬币,分别是1分、5分、10分、15分。然后给出查理拥有的四种硬币的个数,求查理最多可以消耗多少硬币,可以正好买到咖啡而且不需要找钱。


思路:给出每种物品的个数,即为多重背包。不过这题要求的是装满情况下的最多数量,那么数量即为价值。最后要求把每种硬币的数量分别输出,难点就在路径的记录。看的别人的思想,用一个二维数组存储路径,与dp值的更新同步,这种思想值得学习,需要多看!


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

using namespace std;

typedef long long LL;

const int N = 10005;
const int INF = 0x3f3f3f3f;

int dp[N], V, path[N][4], num[10];

void ZeroOnePack(int cost, int weight, int id, int num)
{
    for(int j = V; j >= cost; j--)
    {
        //放入物品后容量为j的最大价值大于不放的最大价值而且前几种物品放入容量为j的价值合法则更新
        if(dp[j-cost]+weight>dp[j] && dp[j-cost]!=-INF)
        {
            dp[j] = dp[j-cost]+weight;
            for(int i = 1; i <= 4; i++)
            {
                //一旦某物被选上,同时所有id的路径都更新,防止更新当前路径时丢掉别的路径
                path[j][i] = path[j-cost][i];
            }
            path[j][id] = path[j][id]+num;
        }
      //  dp[j] = max(dp[j], dp[j-cost]+weight);
    }
}

void CompletePack(int cost, int weight, int id)
{
    for(int j = cost; j <= V; j++)
    {
        if(dp[j-cost]+weight>dp[j] && dp[j-cost]!=-INF)
        {
            dp[j] = dp[j-cost]+weight;
            for(int i = 1; i <= 4; i++)
            {
                path[j][i] = path[j-cost][i];
            }
            path[j][id] = path[j][id]+1;
        }
    }
}

void MultiplePack(int cost, int weight, int amount, int id)
{
    if(cost*amount>=V)
    {
        CompletePack(cost, weight, id);
        return;
    }
    int k = 1;
    while(k < amount)
    {
        ZeroOnePack(cost*k, weight*k, id, k);
        amount-=k;//注意在前面
        k=k*2;
    }
    ZeroOnePack(amount*cost, amount*weight, id, amount);
}

int main()
{
  //  freopen("in.txt", "r", stdin);
    int mon[N], amount[N];
    num[1] = 1;
    num[2] = 5;
    num[3] = 10;
    num[4] = 25;
    while(~scanf("%d%d%d%d%d", &V, &amount[1], &amount[2], &amount[3], &amount[4]))
    {
        if(V==0 && amount[1]==0 && amount[2]==0 && amount[3]==0 && amount[4]==0) break;
        dp[0] = 0;//装满
        for(int i = 1; i < N; i++)
            dp[i] = -INF;
        memset(path, 0, sizeof(path));
        for(int i = 1; i <= 4; i++)
            MultiplePack(num[i], 1, amount[i], i);
      /*  for(int i = 1; i <= V; i++)
        {
            for(int j = 1; j <= 4; j++)
                printf("%d ", path[i][j]);
            printf("\n");
        }
        printf("\n");*/
        if(dp[V] != -INF) printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n", path[V][1], path[V][2], path[V][3], path[V][4]);
        else printf("Charlie cannot buy coffee.\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值