【题解】 【宝物筛选】(NOI导刊2010提高T2)DP背包 二进制拆分

题目来源:洛谷

题目描述

终于,破解了千年的难题。小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小FF可发财了,嘎嘎。但是这里的宝物实在是太多了,小FF的采集车似乎装不下那么多宝物。看来小FF只能含泪舍弃其中的一部分宝物了……小FF对洞穴里的宝物进行了整理,他发现每样宝物都有一件或者多件。他粗略估算了下每样宝物的价值,之后开始了宝物筛选工作:小FF有一个最大载重为W的采集车,洞穴里总共有n种宝物,每种宝物的价值为v[i],重量为w[i],每种宝物有m[i]件。小FF希望在采集车不超载的前提下,选择一些宝物装进采集车,使得它们的价值和最大。

输入格式

第一行为一个整数N和w,分别表示宝物种数和采集车的最大载重。

接下来n行每行三个整数,其中第i行第一个数表示第i类品价值,第二个整数表示一件该类物品的重量,第三个整数为该类物品数量。

输出格式

输出仅一个整数ans,表示在采集车不超载的情况下收集的宝物的最大价值。

输入输出样例

输入 #1
4 20
3 9 3
5 9 1
9 4 2
8 1 3
输出 #1
47

数据范围

对于30%的数据:n≤∑m[i]≤104;0≤W≤103。

对于100%的数据:n≤∑m[i]≤10^5;

0 <w≤4*10^4:1≤n<100。

思路:

这是一道多重背包问题,可是普通的多重背包做法的时间复杂度为O(w∗Σm[i]),这里的w已经到达了4*10^4,再乘上Σm[i]绝对会超时,只能得到30分,那要怎么办呢?

二进制拆分是一个很好的解决办法

将每个物品的数量进行二进制拆分,例如13可以拆成1+2+4+6,将1,2,4,6当成一个个物品,拿4来说,这个物品的价值=单个物品的价值 4,这个物品的重量=单个物品的重量 4,这样的话我们就可以用01背包来做,来判断当前这个物品选还是不选

我讲的很简略,如果不明白的可以看看背包九讲,里面有详细说明

实现起来很简单,看代码:

AC代码:

#include<bits/stdc++.h>
using namespace std;
int n,w,cnt,f[400000];
struct node{
	int v;
	int w;
}a[1000000];
int main()
{
    scanf("%d%d",&n,&w);
    for (int i=1;i<=n;i++)
    {
    	int v,w,num;
    	scanf("%d%d%d",&v,&w,&num);
    	int j;
    	for (j=1;j<=num;j<<=1)
    	{
    		a[++cnt].v=j*v;
    		a[cnt].w=j*w;
    		num-=j;
		}
		if (num!=0) a[++cnt].v=num*v,a[cnt].w=num*w;
	}
	for (int i=1;i<=cnt;i++)
	  for (int j=w;j>=a[i].w;j--)
	     f[j]=max(f[j],f[j-a[i].w]+a[i].v);
	printf("%d\n",f[w]);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值