题意:
k种石头(不用在意具体是什么东西),每种石头的高度为h,这种石头不能处于超过a的高度,数量为c,问最多能用这些石头叠出多大的高度
解题思路:
这是一道稍微有点改动的多重背包题目,被改为每种石头都有一个容量限制。
多重背包的问题我们可以进行转换,对于c*h>=a的石头,在不超过a的条件下,无论去多少块石头都不会用完c,所以就是可以转换为完全背包问题,
而c*h<a的石头,就是c个(价值为h,2*h,....c*h)的01背包问题了,这里可以用二进制加速一下。因为有转换成二进制数后能表示出1到c的所有数,所以效果一样。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=40000;
struct p
{
int a;
int h;
int c;
}x[505];
bool cmp(p a, p b)
{
return a.a<b.a;
}
int f[maxn+5];
void complete(int x, int y)
{
int i;
for(i=x; i<=y; i++)
{
if(f[i-x])f[i]=1;
}
return;
}
void ZeroPack(int x, int y, int z)
{
for(int i=z; i>=x; i--)
{
if(f[i-x])
{
f[i]=1;
}
}
return;
}
int main()
{
int k;
cin>>k;
int i, j;
for(i=0; i<k; i++)
{
scanf("%d%d%d", &x[i].h, &x[i].a, &x[i].c);
}
sort(x, x+k, cmp);
f[0]=1;
for(i=0; i<k; i++)
{
if(x[i].c*x[i].h>=x[i].a)
{
complete(x[i].h, x[i].a);
}
else
{
int e=1;
for(j=x[i].c; j>e; )
{
ZeroPack(e*x[i].h, e, x[i].a);
j-=e;
e<<=1;
}
ZeroPack(j*x[i].h, j, x[i].a);
}
}
for(j=maxn; j>0; j--)
{
if(f[j])break;
}
// for(; j>0; j--)printf("%d\n", f[j]);
printf("%d\n", j);
}