Monkey and Banana
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6221 Accepted Submission(s): 3170
Problem Description
A group of researchers are designing an experiment to test the IQ of a monkey. They will hang a banana at the roof of a building, and at the mean time, provide the monkey with some blocks. If the monkey is clever enough, it shall be able to reach the banana by placing one block on the top another to build a tower and climb up to get its favorite food.
The researchers have n types of blocks, and an unlimited supply of blocks of each type. Each type-i block was a rectangular solid with linear dimensions (xi, yi, zi). A block could be reoriented so that any two of its three dimensions determined the dimensions of the base and the other dimension was the height.
They want to make sure that the tallest tower possible by stacking blocks can reach the roof. The problem is that, in building a tower, one block could only be placed on top of another block as long as the two base dimensions of the upper block were both strictly smaller than the corresponding base dimensions of the lower block because there has to be some space for the monkey to step on. This meant, for example, that blocks oriented to have equal-sized bases couldn't be stacked.
Your job is to write a program that determines the height of the tallest tower the monkey can build with a given set of blocks.
Input
The input file will contain one or more test cases. The first line of each test case contains an integer n,
representing the number of different blocks in the following data set. The maximum value for n is 30.
Each of the next n lines contains three integers representing the values xi, yi and zi.
Input is terminated by a value of zero (0) for n.
Output
For each test case, print one line containing the case number (they are numbered sequentially starting from 1) and the height of the tallest possible tower in the format "Case case: maximum height = height".
Sample Input
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
Sample Output
Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342
题意:题意大致是给出一些积木(x,y,z),利用这些积木如何堆积出最高的高度,其中,上层的积木的长和宽必须严格小于下层的积木,积木可以随便翻转。
思路:一块积木可以有三种堆放方式,即xyz,xzy,yzx.那么对于n块积木,我们有3n种排列情况,我们可以按底面积进行排序(也可以按照x,和y进行排序)。然后用DP
依次求出每种排列情况的最大可能高度,最后再找出每种排列情况的最大可能高度中的最大值,即为全局最大。
动态规划的
初始状态:
DP[i] = Block[i].height.(即初始化状态的每一个排列的最大高度就是对应块积木的高度本身,因为暂时还没有开始两两堆积)
转移式,我们已经按底面积进行从大到小排序了,当我们处理到DP[i]的时候,说明DP[i]之前的最值已经被求出了。DP[i]的初始值是Block[i].height,我们可以遍历
0 <= j <= i之间的积木,并且如果Block[j].area > Block[i].area,说明第i块积木可以堆积到第j块积木上面去,所以,我们尝试将i号积木堆积到j号积木上面,并且记录堆积
之后的高度,如果它比当前的DP[i]要大,更新之,通过这样局部最优找到全局最优解。当处理完0-n时,全部的局部最优解就会得到,到时再遍历一遍数组就能找到全局最优。
#include <iostream>
#include <limits.h>
#include <string>
#include <algorithm>
using namespace std;
// every block has 3 choice
struct block
{
int x,y,z;
};
bool comp(const block& a,const block& b) //
{
if( a.x == b.x)
return a.y > b.y;
return a.x > b.x;
}
block BK[200];
int index,T,ans;
int DP[200];//记录最大高度
void DP_TR()//构造DP表
{
//memset(DP,0,sizeof(DP));这样是wa
int i,j;
for(i=0; i < index; ++i)
{
DP[i] = BK[i].z;
for(j=0; j < i; ++j)
{
if( BK[i].x < BK[j].x && BK[i].y < BK[j].y)//如果j号块比i号块的截面大,则将i号放在j号上面,更新高度
DP[i] = max(DP[i],DP[j]+BK[i].z);
}
}
ans = INT_MIN;
for(i=0; i<index; ++i)
{
if( DP[i] > ans )
ans = DP[i];
}
}
int main()
{
int arr[3],i=1;
while(cin >> T && T !=0 )
{
index = 0;
while( T-- )
{
cin >> arr[0] >> arr[1] >> arr[2];
sort(arr,arr+3);
BK[index].x = arr[0];
BK[index].y = arr[1];
BK[index].z = arr[2];
++index;
BK[index].x = arr[0];
BK[index].y = arr[2];
BK[index].z = arr[1];
++index;
BK[index].x = arr[1];
BK[index].y = arr[2];
BK[index].z = arr[0];
++index;
}
sort(BK,BK+index,comp);
DP_TR();
printf("Case %d: maximum height = %d\n",i++,ans);
}
return 0;
}