题意:有一群牛要上太空,他们计划建一个太空梯(用一些石头垒),他们有k种不同类型的石头,每一种石头的高度为h,数量为c,由于会受到太空辐射,每一种石头不能超过这种石头的最大建造高度a;
我们来简化一下这个问题,现在有n个物品,每个物品的质量为w[i],每个物品有都有c[i]件,问在V为容量的包里的最大价值量是什么,这就是一个多重背包问题。
多重背包(MultiplePack): 有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
这题目和完全背包问题很类似。基本的方程只需将完全背包问题的方程略微一改即可,因为对于第i种物品有n[i]+1种策略:取0件,取1件……取n[i]件。令f[i][v]表示前i种物品恰放入一个容量为v的背包的最大权值,则有状态转移方程:
f[i][v]=max{f[i-1][v-k*c[i]]+k*w[i]|0<=k<=n[i]
但是这道题做出了改变,把背包的容量变成了对高度的限制,在思想上是一样的,我们可以利用多重背包的思想,再加以改动。
这道题目是要求每一种石头不能超过这种石头的最大建造高度a;
那么我们用dp[i][j]表示用前i个物品能不能达到j这个高度
user[i][j]表示第i个物品在高度为j的时候用掉的数量。
我们可以用滚动数组进行优化,dp[i][j]->dp[j] user[i][j]->user[j];
那么dp方程就是dp[j]=dp[j]||dp[j-h[i]] 在转移的同时更新user
答案就是max f[j]==true
如下代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 41000
using namespace std;
struct Node
{
int a,h,c;
}e[N];
bool cmp(const Node& A,const Node &b)
{
return A.a<b.a;
}
int n,Max=0,user[N];
bool dp[N];
int main()
{
scanf("%d",&n);
memset(dp,false,sizeof(dp));
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&e[i].h,&e[i].a,&e[i].c);
}
sort(e+1,e+n+1,cmp);
dp[0]=true;
for(int i=1;i<=n;i++)
{
memset(user,0,sizeof(user));
for(int j=e[i].h;j<=e[i].a;j++)
{
if(!dp[j]&&dp[j-e[i].h]&&user[j-e[i].h]+1<=e[i].c)
{
dp[j]=true;
user[j]=user[j-e[i].h]+1;
if(Max<j)
Max=j;
}
}
}
cout<<Max;
//while(1);
return 0;
}