多重背包问题

本文介绍了如何解决多重背包问题,特别是针对一个具体题目(ZJU 2156),探讨了如何记录每种硬币个数的策略,包括构造预处理数组pre和使用used数组来跟踪硬币使用情况。通过动态规划dp数组,确定每种状态下能用的硬币最大数量,同时确保不超过硬币的实际数量。最后给出了一段C++代码作为解题示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2156

题意:charlie有四种硬币,价值分别为1,5,10,,25,给定每种价值硬币的个数,求出能够刚好买下coffee的硬币的个数,硬币应该尽可能的多,并且选出的硬币的价值之和要正好等于coffee的价值。

类型:多重背包问题

思路:1)在本题中最大的难点在于怎么记录每种硬币的个数。方法是构造一个数组pre,pre[j]=j-b[i],将pre初始化为0,然后将pre[0]初始化为-1。

            2)用一个used数组表示该种硬币的使用情况,used[j]=used[j-b[i]]+1;当used大于该种硬币的数目时,那么就要开始不挑选本种硬币,开始下一层循环。

            3)定义dp数组表示i元最多用多少枚硬币,同时也表示i元能否用已有的硬币表示,真为1,假为0,故首先将dp置为0,然后将dp[0]置为1。

            4)约束条件为if((!dp[j]||dp[j-b[i]]+1>dp[j])&&dp[j-b[i]]&&used[j-b[i]]+1<=a[i]),表示dp[j]为求解,或者dp[j]不够大,并且dp[j-b[i]]不为0(能够用已有的硬币表示)同时,该                   种硬币还足够,那么才能进入循环,进行更新。

#include<cstdio>

#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
#define N 10010
using namespace std;
int n,m;
int a[5],b[5]={0,1,5,10,25};
int dp[N];
int used[N];
int pre[N];
int ans[30];
int main()
{
    int i,j,k;
while(scanf("%d",&m)!=EOF)

    {

int count=m;

        for(i=1;i<=4;i++)

   { 

  scanf("%d",&a[i]);

  count+=a[i];

  }          

 if(!count)  break;
        memset(dp, 0, sizeof(dp));
        memset(pre, 0, sizeof(pre));
        dp[0]=1;
        pre[0]=-1;
        for(i=1;i<=4;i++)
        {
            for(j=0;j<=m;j++)
                used[j]=0;
            for(j=b[i];j<=m;j++)
            {
                if((!dp[j]||dp[j-b[i]]+1>dp[j])&&dp[j-b[i]]&&used[j-b[i]]+1<=a[i])
                {
                    dp[j]=dp[j-b[i]]+1;
                    used[j]=used[j-b[i]]+1;
                    pre[j]=j-b[i];
                }
            }
        }
        memset(ans,0,sizeof(ans));
      if(dp[m])
        {
            for(i=m;pre[i]!=-1;i=pre[i])
                ans[i-pre[i]]++;
            printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n", ans[1], ans[5], ans[10], ans[25]);
        }
        else printf("Charlie cannot buy coffee.\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值