HDU 2844-Coins

本文探讨了一种典型的多重背包问题,即如何利用不同面值的硬币组合来精确支付特定范围内的任意金额。通过详细解析样例数据的过程,提供了一种使用动态规划解决该问题的有效方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Coins

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 16689    Accepted Submission(s): 6624



题目链接:点击打开链接



Problem 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



题意:
有个人想买手表,但是他不知道手表的具体价格,只知道手表的价格不超过 m 元,他现在有 n 种面值的钱,价值A1,A2,A3...An,每种面值的钱有C1,C2,C3...Cn个,先在给你 n 和 m 的值,这人人可能有点强迫症,他想知道从 1 到 m ,有多少个价格可以让他用身上的这些面值的钱正好付足,(比如说有一个 3 元的钱和三个 2 元的钱,假设 m 是 10 的话,那么 2,3,4,5,6,7,9,可以,那么就有 7 种可能)。

分析:
这道题是在做 “悼念512汶川大地震遇难同胞——珍惜现在,感恩生活”题时发现的,别人将它归到多重背包里,最近在刷背包的专题,但对背包理解的还不是很清晰,做悼念512汶川大地震遇难同胞——珍惜现在,感恩生活”这题时,看看题解可以很容易明白,然后这道题卡了两天了,前天问学长,学长说将 dp 数字组的初始值都刷为负无穷,如果你想装满大的背包,你必须先更新小背包,在小背包的基础上去更新大背包,停了两天,想了两天,还是有点迷糊,今天动手将第一组测试数据过程模拟了一遍,好像有点理解,也并不是很清晰的思路吧,先按自己的思路给宝宝们分享一下,有理解不好的地方,看到的宝宝可以给我一个提示哦!(背包为-1,代表该背包不能被正好装满)

这里写图片描述





#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
using namespace std;

const int M=105;
const int INF=0x3f3f3f3f;
int v[M],ans[M];
int dp[100020];
int n,m;
int main()
{
	while(scanf("%d %d",&n,&m)&&(n+m))
    {
		memset(dp,-INF,sizeof(dp));///将dp数组刷为-INF,其实只要是个负数就行
		
		for(int i=0;i<n;i++)
			scanf("%d",&v[i]);///先输入价值
		for(int i=0;i<n;i++)
			scanf("%d",&ans[i]);///再输入对应面值钱的个数
		dp[0]=0;///将dp[0]置为0,因为没有0的东西和钱,dp[0]是个突破口
		for(int i=0;i<n;i++)///外层将n种钱都过一遍
        {
			for(int j=0;j<=m;j++)
            {
				if(dp[j]>=0)///如果dp[0]大于等于0,说明该背包被装满了
					dp[j]=ans[i];///将第i种钱的个数放入装满的背包里存着
				else if(j<v[i] || dp[j-v[i]]<=0)
				 /**第一种是用第i种面值的钱时,一个就超出背包的容量了,不能用;
				第二种是与该背包相差该面值的背包里面没有该面值的钱,
				或是已经用完了,也或者那个背包也为被更新**/
					dp[j]=-1;///就将该背包也置为-1.代表该背包目前不能被装满
				else
					dp[j]=dp[j-v[i]]-1;
					/** 用上了一个第i个硬币,那么首先肯定的是与该背包
					相差v[i]的背包已经装满了,并且里面装入了第i种面值
					的钱的数目。那么用掉一个就减少一个。**/
			}
        }
        int sum=0;
		for(int i=1;i<=m;i++)
			if(dp[i]>=0)///判断,只要背包的值小于0,肯定未装满。
                sum++;
		printf("%d\n",sum);
	}
	return 0;
}











评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值