POJ1742——Coins 多重背包

62 篇文章 2 订阅
6 篇文章 0 订阅

  • 原题如下:

Coins
Time Limit: 3000MS Memory Limit: 30000K
Total Submissions: 32998 Accepted: 11214

Description

People in Silverland use coins.They have coins of value A1,A2,A3...An Silverland dollar.One day Tony opened his money-box and found there were some coins.He decided to buy a very nice watch in a nearby shop. He wanted to pay the exact price(without change) and he known the price would not more than m.But he didn't know the exact price of the watch. 
You are to write a program which reads n,m,A1,A2,A3...An and C1,C2,C3...Cn corresponding to the number of Tony's coins of value A1,A2,A3...An then calculate how many prices(form 1 to m) Tony can pay use these coins. 

Input

The input contains several test cases. The first line of each test case contains two integers n(1<=n<=100),m(m<=100000).The second line contains 2n integers, denoting A1,A2,A3...An,C1,C2,C3...Cn (1<=Ai<=100000,1<=Ci<=1000). The last test case is followed by two zeros.

Output

For each test case output the answer on a single line.

Sample Input

3 10
1 2 4 2 1 1
2 5
1 4 2 1
0 0

Sample Output

8
4

  • 题目大意:给你n种硬币,每种硬币的面值为Ai,数量分别有Ci个。问你能拼凑出小于等于m的多少种面值。
           分析:不难看出是多重背包问题。要优化递推式,记录一下加深印象。

           首先,若dp[i+1][j]为用前i种硬币能否拼出价值j的东西。也就是说存在用前i-1种硬币拼成j,j-Ai,j-2*Ai.....j-Ci*Ai的情况。(类似01背包)这样做时间复杂度太高,所以需要优化。经典的优化方式是,不光求出能否拼成,还求出拼成之后剩多少个该面值的硬币。若是不能拼成就记为-1.这样一来,复杂度就是O(nm)了。但是这样做还是不够好。需要空间太大,所以还需要用滚动数组记录结果。


代码如下

#include <stdio.h>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <queue>
#include <ctype.h>
using namespace std;
#define MAXN 100010
#define INF 100000
int dp[MAXN];
int a[110],c[110];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)
            break;
        for(int i=0;i<n;i++)
            cin>>a[i];
        for(int i=0;i<n;i++)
            cin>>c[i];
        memset(dp,-1,sizeof(dp));
        int cnt=0;
        dp[0]=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<=m;j++)
            {
                if(dp[j]>=0)
                    dp[j]=c[i];
                else if(j<a[i]||dp[j-a[i]]<=0)
                    dp[j]=-1;
                else
                    dp[j]=dp[j-a[i]]-1;
                    
            }
        for(int j=1;j<=m;j++)
            if(dp[j]>=0)
                cnt++;
        printf("%d\n",cnt);
    }
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值