1. 程式人生 > >HDU - 1069 Monkey and Banana(DP)

HDU - 1069 Monkey and Banana(DP)

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”.

輸入n種方塊,並且每種都無限提供,讓你cos一隻聰明的猴子把他們疊起來,要求上面方塊底面的長寬要嚴格小於下面方塊的頂部長寬,問最高疊多高。

雖然題目告訴你無限提供方塊,但是因為有“上面的方塊底面長寬嚴格小於下面的頂部長寬”這一限制,實際上每種方塊最多用6次(6面)。我本來以為是三次,因為一個長方體實際上每兩面是對稱的,但是仔細一想這題里長寬是限死的,所以其實對稱的兩面並不等價。

思考dp,當我們堆好了兩堆,並且發現堆1的頂部長寬都嚴格大於堆2底部長寬,就可以快樂的把它們湊成一堆不用重新算了。

所以把方塊的6種情況都攤開來排個序,然後快樂的取最優堆堆堆,合併合併合併,就得到了答案。

至於排序是升序還是降序其實無所謂…畢竟你不是真的猴子,你可以選擇從上往下堆(霧)。

ac程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 30 * 6 + 5;
int n, dp[maxn];

struct Block {
	int x, y, h;
} b[maxn];

bool cmp(Block &a, Block &b) {
	if(a.x == b.x) {
		return a.y < b.y;
	}
	return a.x < b.x;
}

int main() {
	int kase = 0;
	while(~scanf("%d", &n) && n) {
		memset(dp, 0, sizeof(dp));

		int x, y, h, g = 0;
		for(int i = 0; i < n; i++) {
			scanf("%d%d%d", &x, &y, &h);
			for(int j = 0; j < 3; j++) {
				b[g].x = x, b[g].y = y, b[g].h = h;
				swap(x, h), ++g;
				b[g].x = x, b[g].y = y, b[g].h = h;
				swap(x, y), ++g;
			}
		}

		sort(b, b + g - 1, cmp);

		int ans = 0;
		for(int i = 0; i < g - 1; i++) {
			//dp[i]代表以i號方塊為底部
			dp[i] = b[i].h;
			for(int j = 0; j < i; j++) {
				//然後在小於它寬高的裡面取個最優
				//從小到大dp,在求小的部分的時候已經求出部分最優解,這時候合併兩堆就完事了
				if(b[i].x > b[j].x && b[i].y > b[j].y) {
					dp[i] = max(dp[i], dp[j] + b[i].h);
				}
			}
			//順手記錄個最大值
			ans = max(ans, dp[i]);
		}

		printf("Case %d: maximum height = %d\n", ++kase, ans);
	}
	return 0;
}