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.
思路
這個題意是給你若干種類的長方體,然後你可以任意旋轉他,然後我需要用這些積木搭一個最高的高度,問你可以搭多少。這個題目一看就需要排序對吧,這很顯然,然後我就走向的錯誤的方向,我排序完了之後就開始各種亂七八糟轉移,我本來是想線性去dp每次的取或不取的,但是在推式子的時候發現你當你前一個不取的時候你沒有辦法確定前面的狀態,也就是說沒辦法確定該如何轉移,所以這個方法去世了。那麼現在這種情況我們需要改變一下思路,我們需要從巨集觀的想法去思考一下,我們發現一個性質這個高度是可以疊加的,意思就是我以這塊為底塊的最大高度可以由以倒數第二塊為底塊的加上h得到。那麼問題就簡單了,思路還是一樣,我們需要先排序,關於列舉的順序,我們需要先列舉小的塊,因為這個想法整體的思路是從小狀態推大狀態,那麼我們順序列舉排序後的陣列元素,然後通過列舉前面符合條件的倒數第二塊來轉移出我當前這塊的最高高度。過程中更新答案即可。
程式碼實現
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int inf=0x3f3f3f3f;
void check_min (int &a,int b) {a=min (a,b);}
void check_max (int &a,int b) {a=max (a,b);}
struct node {
int l,s,h;
node (int l,int s,int h):l (l),s (s),h (h) {}
bool operator < (const node &b) const {
if (l==b.l) return s<b.h;
else return l<b.l;
}
};
vector <node> v;
int dp[maxn];
int n;
int main () {
int n,k=0;
while (~scanf ("%d",&n)) {
k++;
if (n==0) break;
v.clear ();
for (int i=1,a,b,c;i<=n;i++) {
scanf ("%d%d%d",&a,&b,&c);
v.push_back ({a,b,c});
v.push_back ({b,a,c});
v.push_back ({c,b,a});
v.push_back ({c,a,b});
v.push_back ({a,c,b});
v.push_back ({b,c,a});
}
sort (v.begin (),v.end ());
memset (dp,0,sizeof (dp));
int ans=0;
for (int i=0;i<v.size ();i++) {
int st=v[i].h;
dp[i]=st;
for (int j=i-1;j>=0;j--) {
if (v[j].l<v[i].l&&v[j].s<v[i].s&&dp[j]+st>dp[i]) dp[i]=dp[j]+st;
}
check_max (ans,dp[i]);
}
printf ("Case %d: maximum height = %d\n",k,ans);
}
return 0;
}