題目描述
一組研究人員正在設計一項實驗,以測試猴子的智商。他們將掛香蕉在建築物的屋頂,同時,提供一些磚塊給這些猴子。如果猴子足夠聰明,它應當能夠通過合理的放置一些磚塊建立一個塔,並爬上去喫他們最喜歡的香蕉。
研究人員有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;
}