HDU - 1069 DP

Monkey and Banana

题目大意:

给你n种长方体,每种立方体都有个长宽高,每种立方体有无数个,让你选择任意立方体堆起来,要求上面的长和宽都严格小于下面的长和宽,问你最高能堆多高。

数据范围:

0<n30,多组输入到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\n", ++tot, Maxm);
    }
    return 0;
}
posted @ 2018-04-19 23:27  呵呵!!!  阅读(119)  评论(0编辑  收藏  举报