HDOJ3449 Consumer -----依赖背包(经典题)

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=3449

Problem Description

FJ is going to do some shopping, and before that, he needs some boxes to carry the different kinds of stuff he is going to buy. Each box is assigned to carry some specific kinds of stuff (that is to say, if he is going to buy one of these stuff, he has to buy the box beforehand). Each kind of stuff has its own value. Now FJ only has an amount of W dollars for shopping, he intends to get the highest value with the money.

 

 

Input

The first line will contain two integers, n (the number of boxes 1 <= n <= 50), w (the amount of money FJ has, 1 <= w <= 100000) Then n lines follow. Each line contains the following number pi (the price of the ith box 1<=pi<=1000), mi (1<=mi<=10 the number goods ith box can carry), and mi pairs of numbers, the price cj (1<=cj<=100), the value vj(1<=vj<=1000000)

 

 

Output

For each test case, output the maximum value FJ can get

 

 

Sample Input

 

3 800 300 2 30 50 25 80 600 1 50 130 400 3 40 70 30 40 35 60

 

 

Sample Output

 

210

题意::有n组物品,每组对应一个盒子,每组有若干件物品,要买物品必须先买盒子,有w元,问最多能得到的价值。

题解:这是典型的依赖背包问题。对于每组,有2种选择:①什么都不买 ②买至少一样东西(含盒子)

如果是前者,那么最大价值等于计算前一组物品时算出的最大价值。

所以dp数组遍历每组时,先用tmp临时保存上一组结果,然后只考虑②,所以必须先把盒子买了,再对该组01背包。

因为考虑②时前提是必须买得起盒子,如果dp[j]的j小了买不起盒子,那就得标记好排除这种情况。

题解参考自博客 https://www.cnblogs.com/cmmdc/p/7830975.html

	#include <cstdio>
	#include <cstring>
	#include <algorithm>
	using namespace std;	
	int n,w;
	int dp[100005];
	int num[55];// 记录每组物品个数
	int priceOfBox[55];// 盒子价格 
	int price[55][15];// 物品花费 
	int value[55][15];// 物品价值 
	int dp_tmp[100005]; // 临时数组 
	
	int main()
	{
	    while(scanf("%d%d",&n,&w) != EOF) {
	        memset(dp,0,sizeof(dp));
		    for(int i = 1;i <= n;i++) {
		        scanf("%d",&priceOfBox[i]);
		        scanf("%d",&num[i]);
		        for(int j = 1;j <= num[i];j++) {
		            scanf("%d%d",&price[i][j],&value[i][j]);
		        } 
		    }
		    for(int i = 1;i <= n;i++)  {
		        memcpy(dp_tmp,dp,sizeof(dp));
		        // 买不起盒子,打好标记 
		        for(int j = 0;j < priceOfBox[i];j++)
		            dp[j] = -1;
		        for(int j = priceOfBox[i];j <= w;j++)    
		            dp[j] = dp_tmp[j-priceOfBox[i]];
		        for(int j = 1;j <= num[i];j++) {				        	
		            for(int k = w;k >= price[i][j];k--) {
						if(dp[k-price[i][j]] != -1)									            		
		                	dp[k] = max(dp[k],dp[k-price[i][j]] + value[i][j]);
		            }
		        }
		        for(int j = 0;j <= w;j++)    
		            dp[j] = max(dp_tmp[j],dp[j]);
		    }
		    
		    printf("%d\n",dp[w]);
	    }
	   return 0;
	} 
	
	

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值