题目描述
一组研究人员正在设计一项实验,以测试猴子的智商。他们将挂香蕉在建筑物的屋顶,同时,提供一些砖块给这些猴子。如果猴子足够聪明,它应当能够通过合理的放置一些砖块建立一个塔,并爬上去吃他们最喜欢的香蕉。
研究人员有n种类型的砖块,每种类型的砖块都有无限个。第i块砖块的长宽高分别用xi,yi,zi来表示。 同时,由于砖块是可以旋转的,每个砖块的3条边可以组成6种不同的长宽高。
在构建塔时,当且仅当A砖块的长和宽都分别小于B砖块的长和宽时,A砖块才能放到B砖块的上面,因为必须留有一些空间让猴子来踩。
你的任务是编写一个程序,计算猴子们最高可以堆出的砖块们的高度。
输入格式
输入文件包含多组测试数据。
每个测试用例的第一行包含一个整数n,代表不同种类的砖块数目。n<=30.
接下来n行,每行3个数,分别表示砖块的长宽高。
当n= 0的时候,无需输出任何答案,测试结束。
输出格式
对于每组测试数据,输出最大高度。格式:Case 第几组数据: maximum height = 最大高度
样例输入
1
10 20 30
2
6 8 10
5 5 5
7
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
0
样例输出
Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342
题解:
- 对于每一块砖,有三条边可以作为高,则另外两条边可分别做长、宽,故共有6种摆法
- 将6*n种砖加入到数组中,再将其按长度递增排序(长度相等则宽度递增)
- 定义状态dp[i]为将第i个箱子作为最底部时的最高高度,因已保证长度递增,所以只需要判断宽度和长度是否严格递增。如此一来,问题便变得像最长递增子串了。
- 状态转移:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 35 * 6;
struct box{
int l,w,s,h;
};
bool cmp(box &a, box &b)
{
if(a.l==b.l) return a.w < b.w;
return a.l < b.l;
}
box bo[maxn];
int dp[maxn];
int solve(int sn)
{
int ans = 0;
for(int i=0;i<sn;i++)
{
dp[i] = bo[i].h;
for(int j=0;j<i;j++)
if(bo[j].l<bo[i].l && bo[j].w < bo[i].w && dp[j]+bo[i].h > dp[i])
dp[i] = dp[j]+bo[i].h;
ans = max(ans, dp[i]);
}
return ans;
}
int main()
{
int n,kase = 0;
cin >> n;
while(n)
{
int a,b,c;
for(int i=0;i<n;i++)
{
scanf("%d %d %d",&a,&b,&c);
// 六种摆法
bo[i*6+5].h = bo[i*6+4].w = bo[i*6+3].l = bo[i*6+2].h = bo[i*6+1].w = bo[i*6].l = a;
bo[i*6+5].l = bo[i*6+4].h = bo[i*6+3].w = bo[i*6+2].w = bo[i*6+1].l = bo[i*6].h = b;
bo[i*6+5].w = bo[i*6+4].l = bo[i*6+3].h = bo[i*6+2].l = bo[i*6+1].h = bo[i*6].w = c;
}
int sn = 6*n;
sort(bo, bo+sn, cmp);
cout <<"Case " << ++kase << ": maximum height = " << solve(sn) << endl;
scanf("%d",&n);
}
return 0;
}