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;
}
posted @ 2019-11-17 12:23  ALKING1001  阅读(89)  评论(0编辑  收藏  举报