题目来源:洛谷
题目描述
终于,破解了千年的难题。小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;
}