#2020.02.04训练题解#背包入门(D题)

题源HDU-2844

HDU-2844-Coins

Description
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和一个V,代表有N种硬币和价格上限
  • 接下来输入N种硬币的面值和N个硬币的数额,分别对应
  • 最后输出可用所有硬币拼成多少种上限价格及以内的数值
  • 注意多组输入,当N和V都为零的时候程序结束

题解

  • 这是多重背包模板题,对模板进行微改即可
  • 注意 原模板的m[i]意义应当是每种硬币的个数,此处即为输入cost[i]
  • dp[i]指的是容量为i的袋子最多装入多少价值的硬币
  • 在此题中,如果数值 i 用现有的硬币拼出,那么应当有dp[i]==i
  • 所以在原模板函数内部遍历判断,用ans初始化计数即可
  • 详见代码行注释

涉及知识点

  • 背包 算法(此题属于多重背包)
  • 对于背包的算法-详见链接博客介绍背包

AC代码

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int T,n,v,value[maxn],value1[maxn],cost[maxn],dp[maxn];//dp[maxn][maxn]二维数组 
int knapsack_multiple()//多重背包 
{
	int n1=0;
	memset(value1,0,sizeof(value1));
	memset(dp,0,sizeof(dp));
	for(int i=1;i<=n;++i)
	{
		for(int j=1;cost[i];j*=2)//二进制优化拆数1 2 4 8 16 32等等 
		{
			j=min(j,cost[i]);
			/*
				比如29拆成1 2 4 8 14,此步骤处理类似剩余14,不足16的情况
				即当前的j与剩余的总数量取最小值
				全部取完的话cost[i]==0为假,循环就退出了 
			*/ 
			cost[i]-=j;
			n1++;
			value1[n1]=value[i]*j;
			/*
				靠二进制排列组合,能组出1-上界各数
				下文对value1遍历取或不取,排列组合即可
				value1是取各二进制个物品的价值 
			*/
		}
	}
	for(int i=1;i<=n1;++i)
	{
		for(int j=v;j>=value1[i];--j)
		{
			dp[j]=max(dp[j],dp[j-value1[i]]+value1[i]);
		}
	}
	int ans=0;
	for(int i=1;i<=v;++i)
	{
		if(dp[i]==i) ans++;
		/*
			dp[i]代表体积为i的袋子里面最多能装多少价值的物品 
			故如果这个价格能被硬币拼出来
			这个体积的袋子就得装满咯 
		*/
	}
	return ans;
}
int main()
{
	while(~scanf("%d %d",&n,&v)&&n+v)
	{
		memset(value,0,sizeof(value));
		memset(cost,0,sizeof(cost));
		for(int i=1;i<=n;++i) scanf("%d",&value[i]);//价值 
		for(int i=1;i<=n;++i) scanf("%d",&cost[i]);//数量 
		printf("%d\n",knapsack_multiple());
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值