HDU 2844 Coins (多重背包)

Coins

Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One day Hibix opened purse 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种货币,M表示一个上限。第二行有2N个数,前N个数是货币的面值,后N个数对应货币的个数。求这N种货币能组成多少个总价值在1到M的货币组合。

ps:比如第一个样例:3种货币分别是2个1元,1个2元,1个4元。可以组成面值为1,2,3,4,5,6,7,8的8种组合。

题解:将多重背包分解成01背包和完全背包,01背包再用二进制优化。

贴一个模板级的代码:

#include<stdio.h>
int a[110],c[110],dp[100010];

int maxn(int i,int j) {return i > j ? i : j;}
void CompletePack(int v,int w,int m)
{
    for(int j=v; j<=m; j++)
        dp[j] = maxn(dp[j],dp[j-v]+w);
}
void ZeroOnePack(int v,int w,int m)
{
    for(int j=m; j>=v; j--)
        dp[j] = maxn(dp[j],dp[j-v]+w);
}
void MultiPack(int v,int w,int m,int c)
{
    if(v*c > m) CompletePack(v,w,m);
    else
    {
        int k = 1;
        while(k < c)
        {
            ZeroOnePack(k*v,k*w,m);
            c -= k;
            k *= 2;
        }
        ZeroOnePack(c*v,c*w,m);
    }
}
int main()
{
    int i,j,n,m;

    while(~scanf("%d%d", &n,&m),n+m)
    {
        for(i=1; i<=m; i++) dp[i] = 0;
        for(i=1; i<=n; i++)
            scanf("%d", a+i);
        for(i=1; i<=n; i++)
            scanf("%d", c+i);
        for(i=1; i<=n; i++)
            MultiPack(a[i],a[i],m,c[i]);
        int sum = 0;
        for(i=1; i<=m; i++)
            if(dp[i] == i) sum++;
        printf("%d\n", sum);
    }
    return 0;
}

博主代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
int v[110];
int w[110];
int dp[100005];
using namespace std;
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        memset(v,0,sizeof(v));
        memset(w,0,sizeof(w));
        for(int i=1;i<=100005;i++)
        dp[i]=-9999999;
        dp[0]=1;
        for(int i=1; i<=n; i++)
            scanf("%d",&v[i]);
        for(int i=1; i<=n; i++)
            scanf("%d",&w[i]);
        for(int i=1; i<=n; i++)
        {
            if(v[i]*w[i]>=m)//转化成完全背包
            {
                for(int j=v[i]; j<=m; j++)
                {
                    dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
                    //printf("%d %d\n",j,dp[j]);
                }
            }
            else//转化成01背包
            {
                for(int k=1; k<=w[i]; k=k*2)//二进制优化
                {
                    for(int j=m; j>=v[i]*k; j--)
                    {
                        dp[j]=max(dp[j],dp[j-v[i]*k]+v[i]*k);
                    }
                     w[i]-=k;
                }
                if(w[i]>0)
                {
                    for(int j=m; j>=v[i]*w[i]; j--)
                        dp[j]=max(dp[j],dp[j-v[i]*w[i]]+v[i]*w[i]);
                }
            }
        }
        int count=0;
        for(int i=1; i<=m; i++)
        {
            if(dp[i]>=0)
                count++;
        }
        printf("%d\n",count);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42391248/article/details/81265083