Monkey and Banana
题目大意:
给你n种长方体,每种立方体都有个长宽高,每种立方体有无数个,让你选择任意立方体堆起来,要求上面的长和宽都严格小于下面的长和宽,问你最高能堆多高。
数据范围:
,多组输入到n为0时结束输入。
解题思路:
每种立方体又可分为三种立方体,即一共有3n个立方体,而每个立方体由于不可能使得底面相同,所以最多只能选一个,这时就可以确定一个状态,dp[i]代表以第i个立方体为底时可得的最大高度,即第i个状态可从前i-1个状态转移过来,即
for(int j = 1; j < i; j++) {
if(ans[i].a > ans[j].a && ans[i].b > ans[j].b) {
dp[i] = max(dp[i], dp[j] + ans[j].c);//(其中ans[j].c为第j个块的高度)
}
}
但是这样的话,如果大的底在前面的话就不能保证答案的正确,可以将数组重复3n次,那么每个数都能跑到,但是这样就导致复杂度接受不了,单n等于30是就接近1e8了,还是多组,果断TLE了,所以,可以对底边从小到大排序一下,保证小底在前,就能AC了。(仔细想想,确定了宽是从小到大,宽相同时长按小到大,是能保证答案正确的,因为假如当前立方体宽较小而长较长,那么即使将它的被访问顺序往后挪的话,那么即使长度能满足了,那么宽度便满足不了了)
AC代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 10000;
typedef long long LL;
LL dp[maxn + 5];
int n, tot;
struct NOOD {
LL a, b, c;
}ans[maxn+ 5];
bool cmp(NOOD x, NOOD y) {
if(x.a == y.a)return x.b < y.b;
return x.a < y.a;
}
int main() {
while(~scanf("%d", &n) && n) {
int t = 0;
LL Maxm = 0;
memset(dp, -1, sizeof(dp));
for(int i = 1; i <= n; i++) {
LL x, y, z;
scanf("%lld%lld%lld", &x, &y, &z);
ans[++t].a = x, ans[t].b = y, ans[t].c = z;
ans[++t].a = z, ans[t].b = x, ans[t].c = y;
ans[++t].a = y, ans[t].b = z, ans[t].c = x;
}
for(int i = 1; i <= t; i++) if(ans[i].a > ans[i].b)swap(ans[i].a, ans[i].b);
sort(ans + 1, ans + t + 1, cmp);
dp[1] = ans[1].c;
Maxm = dp[1];
for(int i = 2; i <= t; i++) {
dp[i] = ans[i].c;
for(int j = 1; j < i; j++) {
if(ans[i].a > ans[j].a && ans[i].b > ans[j].b) {
dp[i] = max(dp[i], dp[j] + ans[i].c);
}
}
Maxm = max(Maxm, dp[i]);
}
printf("Case %d: maximum height = %lld
", ++tot, Maxm);
}
return 0;
}