Space Elevator
- Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
The cows are going to space! They plan to achieve orbit by building a sort of space elevator: a giant tower of blocks. They have K (1 ≤ K ≤ 400) different types of blocks with which to build the tower. Each block of type i has height hi (1 ≤ hi ≤ 100) and is available in quantity ci (1 ≤ ci ≤ 10). Due to possible damage caused by cosmic rays, no part of a block of type i can exceed a maximum altitude ai (1 ≤ ai ≤ 40000).
Help the cows build the tallest space elevator possible by stacking blocks on top of each other according to the rules.
* Line 1: A single integer, K
* Lines 2..K+1: Each line contains three space-separated integers: hi, ai, and ci. Line i+1 describes block type i.
* Line 1: A single integer H, the maximum height of a tower that can be built
3
7 40 3
5 23 8
2 52 6
48
OUTPUT DETAILS:
From the bottom: 3 blocks of type 2, below 3 of type 1, below 6 of type 3. Stacking 4 blocks of type 2 and 3 of type 1 is not legal, since the top of the last type 1 block would exceed height 40.
题目意思:
有K组数,后面三个数h,a,c分别表示一块砖的高度 h 、用这种砖的最大限制高度 a 和用这种砖的最多块数 c 。求用这些砖叠在一起的最大高度;
两种解题方法:
① 转化为由多重背包--->01背包;(注:与其他普通的01背包不同的是每种i砖的使用有一个高度限制a)
② 使用多重部分和的思想 限制条件为最大高度;
① 多重背包--->01背包 AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 40005
int dp[MAXN];//d[i]表示石块能组成的高度为i
///容量即价值
struct Node
{
int h,a,c;//分别表示一块砖的高度、用这种砖的最大高度和最多块数
} s[MAXN];
int cmp(Node x,Node y)//结构体排序
{
return x.a<y.a;//升序
}
int main()
{
int n,i,j,k,ans=0;
cin>>n;
for(i=0; i<n; ++i)
cin>>s[i].h>>s[i].a>>s[i].c;///因为每块砖的高度限制条件不一样
///所以不能将所有砖的数量直接在这用二进制进行分解
sort(s,s+n,cmp);//按最大高度升序排列
memset(dp,0,sizeof(dp));//初始化
for(i=0; i<n; ++i)//n种砖块,使用多重背包
{
if(s[i].h*s[i].c>=s[i].a)//完全背包
for(j=s[i].h; j<=s[i].a; j++)
dp[j]=max(dp[j],dp[j-s[i].h]+s[i].h);
else//01背包
{
for(k=1; k<=s[i].c; k<<=1) //二进制优化分解数量
{
for(j=s[i].a; j>=k*s[i].h; --j)///砖块使用的限制高度
dp[j]=max(dp[j],dp[j-k*s[i].h]+k*s[i].h);///容量即价值
s[i].c-=k;//减去用过的数量
}
if(s[i].c>0) ///还剩余未分解完的
for(j=s[i].a; j>=s[i].h*s[i].c; --j)
dp[j]=max(dp[j],dp[j-s[i].h*s[i].c]+s[i].h*s[i].c);
}
}
for(i=1; i<=s[n-1].a; ++i)///s[n-1].a表示所有限制高度中价值的最大值
ans=max(ans,dp[i]);///找出石块能组成的最大高度
cout<<ans<<endl;
return 0;
}
② 多重部分和AC代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 40005
int dp[MAXN];//d[i]表示能组成的i高度时 还剩有几块石块
struct Node
{
int h,a,c;//分别表示一块砖的高度、用这种砖的最大高度和最多块数
} s[MAXN];
int cmp(Node x,Node y)//结构体排序
{
return x.a<y.a;//升序
}
int main()
{
int n,i,j,ans=0;
cin>>n;
for(i=0; i<n; ++i)
cin>>s[i].h>>s[i].a>>s[i].c;
sort(s,s+n,cmp);//按最大高度 升序排列 从低到高
memset(dp,-1,sizeof dp);
///以下 以从低开始建楼的思路 来想 即必须有已建好的高度 才可以在前面的高度上 加高
dp[0]=0;///从0开始建塔 地基
for(i=0; i<n; i++)///每种砖头 多重部分和
for(j=0; j<=s[i].a; j++)///第i种砖头所能组成塔的最大高度
{
if (dp[j]>=0) dp[j]=s[i].c; ///塔高j已组成,所以在建好塔高j时 第i种砖还剩有s[i].c个块可用
else if (j<s[i].h || dp[j-s[i].h] <=0) dp[j]=-1; ///塔高<块高 || 塔高 j-s[i].h 在之前还没组成(砖块高无法组成的塔高)
else if (j>=s[i].h && dp[j-s[i].h]>0) ///塔高>=块高 && j-s[i].h 高的塔已存在
dp[j] = dp[j-s[i].h]-1;///用 s[i].h 组成塔高j后,用了一个 i型的砖 剩余砖块减1
}
for (i=s[n-1].a; i>=0; --i)
if(dp[i]>=0)
{
ans=i;
break;
}
cout<<ans<<endl;
return 0;
}