poj1276 Cash Machine-多重背包

 Cash Machine

Description

A Bank plans to install a machine for cash withdrawal. The machine is able to deliver appropriate @ bills for a requested cash amount. The machine uses exactly N distinct bill denominations, say Dk, k=1,N, and for each denomination Dk the machine has a supply of nk bills. For example,

N=3, n1=10, D1=100, n2=4, D2=50, n3=5, D3=10

means the machine has a supply of 10 bills of @100 each, 4 bills of @50 each, and 5 bills of @10 each.

Call cash the requested amount of cash the machine should deliver and write a program that computes the maximum amount of cash less than or equal to cash that can be effectively delivered according to the available bill supply of the machine.

Notes:
@ is the symbol of the currency delivered by the machine. For instance, @ may stand for dollar, euro, pound etc.

Input

The program input is from standard input. Each data set in the input stands for a particular transaction and has the format:

cash N n1 D1 n2 D2 ... nN DN

where 0 <= cash <= 100000 is the amount of cash requested, 0 <=N <= 10 is the number of bill denominations and 0 <= nk <= 1000 is the number of available bills for the Dk denomination, 1 <= Dk <= 1000, k=1,N. White spaces can occur freely between the numbers in the input. The input data are correct.

Output

For each set of data the program prints the result to the standard output on a separate line as shown in the examples below.

Sample Input

735 3  4 125  6 5  3 350
633 4  500 30  6 100  1 5  0 1
735 0
0 3  10 100  10 50  10 10

Sample Output

735
630
0
0

Hint

The first data set designates a transaction where the amount of cash requested is @735. The machine contains 3 bill denominations: 4 bills of @125, 6 bills of @5, and 3 bills of @350. The machine can deliver the exact amount of requested cash.

In the second case the bill supply of the machine does not fit the exact amount of cash requested. The maximum cash that can be delivered is @630. Notice that there can be several possibilities to combine the bills in the machine for matching the delivered cash.

In the third case the machine is empty and no cash is delivered. In the fourth case the amount of cash requested is @0 and, therefore, the machine delivers no cash.

题目大意

给你一个总钱数cash,N种货币,每种有n个,问这些货币最多能拼成多少钱,使之最接近cash。

解题思路

思路一、多重背包的模板题,推荐看背包九讲

本来用的基本方法,结果超时了,果然还是得用优化的。心塞

其实就是转化为价值和消耗相等的01背包,把每种物品分解为多种物品,然后使用01背包求解。基本思路是枚举k ,让k*原参数成为一个新的物品,这样1个物品就变成了n个物品。

事实上这种办法容易超时,需要优化

考虑这样一个问题,真的需要枚举每个k吗?

例如某种物品数量为13,那么可以分解为1.2.3.4.5……13,这样每个数都能达到,但是拿取1和3是不是相当于拿取4呢?同样 拿取6 7是不是直接相当于拿取13呢

于是我们希望优化系数,想到二进制的思想,2进制可以表示任意数,如果我们把13分解为 1 2 4 6,这样会发现,1~13中每一个数都能用其中任意一个或多个相加来表示。

至于k,我们规定 n-2^k+1>0,最后一个 系数  是 总数 - 满足条件的所有k。


思路二、枚举面值

还有一种思想是枚举面值,如果面值为j可以达到,那么面值为 j+k*cost[i] (k属于n[i])也能达到.解题过程中就记录更新最大的面值。



代码
思路一
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int cash,n,i,j,k;
int dp[100010],num[11000],cost[11000];

void zeroonepack(int cost)
{
    int i;
    for(i=cash;i>=cost;--i)
    {
       dp[i]= max(dp[i-cost]+cost,dp[i]);
    }
}

void complete_pack(int cost)
{
    int i;
    for(i=cost;i<=cash;++i)
        dp[i]=max(dp[i],dp[i-cost]+cost);
}

void multiple_pack(int n,int cost)
{
    if(n*cost>=cash)//相当于这个物品有无限件,完全背包
        complete_pack(cost);
    else
    {
        int k=1;
        while(k<n)
        {
            zeroonepack(cost*k);
            n-=k;
            k*=2;
        }
        zeroonepack(cost*n);
    }
}
int main()
{

    while(scanf("%d",&cash)!=EOF)
    {


        scanf("%d",&n);
        for(i=0;i<n;++i)
            scanf("%d%d",&num[i],&cost[i]);
        if(!cash || !n) printf("0\n");
        else
        {
            memset(dp,0,sizeof(dp));
            for(i=0;i<n;++i)
            {
                multiple_pack(num[i],cost[i]);
            }
            printf("%d\n",dp[cash]);
        }
    }
    return 0;
}


思路二
#include<cstdio>
#include <cstring>
using namespace std;
int cash,n,i,j,k,maxn=0;
int dp[100010],num[11000],cost[11000];
int main()
{
    while(scanf("%d",&cash)!=EOF)
    {
        scanf("%d",&n);
        for(i=0;i<n;++i)
            scanf("%d%d",&num[i],&cost[i]);
        if(!cash || !n) printf("0\n");
        else
        {
            maxn=0;
            memset(dp,0,sizeof(dp));
            dp[0]=1;
            for(i=0;i<n;++i)
            {
                for(j=maxn;j>=0;j--)
                {
                    if(dp[j])
                    {
                        for(k=1;k<=num[i];++k)
                        {
                            int t=j+k*cost[i];
                            if(t<=cash)
                            {
                                dp[t]=1;
                                if(t>maxn)
                                    maxn=t;
                            }
                        }
                    }
                }
            }

            printf("%d\n",maxn);
        }
    }

    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的影城管理系统,源码+数据库+论文答辩+毕业论文+视频演示 随着现在网络的快速发展,网上管理系统也逐渐快速发展起来,网上管理模式很快融入到了许多生活之中,随之就产生了“小徐影城管理系统”,这样就让小徐影城管理系统更加方便简单。 对于本小徐影城管理系统的设计来说,系统开发主要是采用java语言技术,在整个系统的设计中应用MySQL数据库来完成数据存储,具体根据小徐影城管理系统的现状来进行开发的,具体根据现实的需求来实现小徐影城管理系统网络化的管理,各类信息有序地进行存储,进入小徐影城管理系统页面之后,方可开始操作主控界面,主要功能包括管理员:首页、个人中心、用户管理、电影类型管理、放映厅管理、电影信息管理、购票统计管理、系统管理、订单管理,用户前台;首页、电影信息、电影资讯、个人中心、后台管理、在线客服等功能。 本论文主要讲述了小徐影城管理系统开发背景,该系统它主要是对需求分析和功能需求做了介绍,并且对系统做了详细的测试和总结。具体从业务流程、数据库设计和系统结构等多方面的问题。望能利用先进的计算机技术和网络技术来改变目前的小徐影城管理系统状况,提高管理效率。 关键词:小徐影城管理系统;Spring Boot框架,MySQL数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值