HDU 2844 Coins 多重背包

HDU 2844 Coins 多重背包

题意

给你n种硬币,每个硬币的金额为\(Ai\),数量为\(Ci\),然后给你一个范围\(m\),问在使用这些硬币可以组成多少种金额,要求组成的金额在\((1, m)\)范围内。

解题思路

使用多重背包来进行解决这个问题。这样我们能够获得每种金额(可以看作背包的容量)下使用硬币组成的最多的金额数量。二重背包结束后,然后使用for循环,遍历这里dp里面\(dp[i]==i\)的个数,这个个数就是答案。

代码实现

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=107; //硬币的种类数量
const int maxm=1e5+7; //金额的最大范围
int a[maxn], c[maxn];
int n, m;
int dp[maxm];
int main()
{
    while(scanf("%d%d", &n, &m) && (n+m)!=0)
    {
        for(int i=1; i<=n; i++)
            scanf("%d", &a[i]);
        for(int i=1; i<=n; i++)
            scanf("%d", &c[i]);
        memset(dp, 0, sizeof(dp));
        //下面就是二重背包的主要代码,可以说就是模板了
        for(int i=1; i<=n; i++) //遍历前i种硬币
        {
            int min_num=min(c[i], m/a[i]); //选择这种硬币的最少数量
            for(int k=1; min_num>0; k<<=1) //使用二进制优化
            {
                if(k>min_num) //如果最后不够k个了,就直接赋值给k
                    k=min_num;
                min_num-=k;
                for(int j=m; j>=a[i]*k; j--)
                {
                    dp[j]=max(dp[j], dp[j-a[i]*k]+a[i]*k);
                }
            }   
        }
        int ans=0;
        for(int i=1; i<=m; i++)//这里遍历一遍dp里面dp[i]==i的个数
            if(dp[i]==i)
                ans++;
        printf("%d\n", ans); //输出个数就是答案
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/alking1001/p/11875939.html