HDOJ 3449【Consumer】

题目链接

存疑:第一种代码为何WA?

思路:

  • 注意题面没说多组用例,但是实际上是,很坑。
  • 依赖背包,即每组中的物品由一个主件和若干附件组成,若买任意附件则必须先买主件。本题中主件价值为零,价格倒是挺贵。
  • 首先按照背包九讲中的做法,不知为何WA:对每一组中的物品先进行一次Sub_Pack(详见背包九讲)。再对物品进行Main_Pack。(均为01Pack)

代码:

  • WA:858MS 1816K
//858MS		1816K


#include <iostream>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MIN 0xc0c0c0c0

using namespace std;

const int maxw = 100005;
const int sub_maxw = 2005;
const int maxn = 15;//sub

int num,W;
int dp[maxw];
int sub_dp[sub_maxw];
int w[maxn];
int v[maxn];


int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>num>>W){
		//题中没确定说多组用例,很坑。 
		memset(dp,0,sizeof(dp));
		for(int k=1;k<=num;k++){
			int p,n;
			cin>>p>>n;
			for(int i=1;i<=n;i++)
				cin>>w[i]>>v[i];
			//Sub_NormalPack:
			memset(sub_dp,MIN,sizeof(sub_dp));//使其装满
			sub_dp[0] = 0;
			
			for(int i=1;i<=n;i++){
				for(int j = sub_maxw - 1 ; j >= w[i] ; j--){
					//注意是01背包,虽然题意不明确,但是通过每个盒子最多能装n种而且给了n个商品可以判断出来
					sub_dp[j] = max(sub_dp[j] , sub_dp[j - w[i]] + v[i]);//先不带主件,这样好想 
				}
			}
			
			for(int j = sub_maxw-1 ; j >= p ; j--)
				sub_dp[j] = sub_dp[j - p];
			
			//Main_NormalPack:
			for(int i = p ; i < sub_maxw ; i++){
				if(sub_dp[i] <= 0)
					continue;
				for(int j=W;j>=i;j--)
					dp[j] = max(dp[j] , dp[j-i] + sub_dp[i]);
			}
		}
		cout<<dp[W]<<endl;
	}
	return 0;
}

思路:

  • 此路不通,考虑在处理每组物品之前,使用一个主dp数组的复制品sub_dp,然后对本组物品在sub_dp中直接01PackPack之后再通过串格的方式加入盒子的价钱。注意可能会有从未买本组物品的格子它们的代价也被加上了一个盒子的价钱,但是这在判断是否采用新格子的时候就被消除了不良影响。
  • 注意这种方法sub_dp数组的大小要迁就dp数组。

代码:

  • AC代码:187MS 2200K
//187MS		2200K


#include <iostream>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define MIN 0xc0c0c0c0

using namespace std;

const int maxw = 100005;
const int maxn = 15;//sub

int num,W;
int dp[maxw];
int sub_dp[maxw];
int w[maxn];
int v[maxn];


int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	while(cin>>num>>W){
		//题中没确定说多组用例,很坑。 
		memset(dp,0,sizeof(dp));
		for(int k=1;k<=num;k++){
			int p,n;
			cin>>p>>n;
			for(int i=1;i<=n;i++)
				cin>>w[i]>>v[i];
			
			memcpy(sub_dp,dp,sizeof(dp));
			
			for(int i=1;i<=n;i++){
				for(int j=W;j>=w[i];j--){
					//注意是01背包,虽然题意不明确,但是通过每个盒子最多能装n种而且给了n个商品可以判断出来
					sub_dp[j] = max(sub_dp[j] , sub_dp[j - w[i]] + v[i]);//先不带主件,这样好想 
				}
			}
			for(int j = W ; j >= p ; j--)
				sub_dp[j] = sub_dp[j - p];
			for(int i=p;i<=W;i++)
				dp[i] = max(dp[i] , sub_dp[i]);
		}
		cout<<dp[W]<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值