HDOJ 1069 Monkey and Banana(LIS)

26 篇文章 0 订阅

题意,给出 n 种长方体的 a, b, c,每种都有无限多个,把它们盖成一个塔,要求相邻的下层长和宽都要严格大于上层。

刚开始想了个DAG上动态规划的做法(感觉直观上第一反应就是这种做法啊。。。)但是貌似有点小问题,虽然样例能过,但是会 STACK_OVERFLOW ,然后以为是记忆化搜索的问题,改成非递归的,直接 TLE 了。。。

于是上网找了正解。。。

显然每个长方体都有三种不同的形态,因为题目要求严格小于,所以每种长方体最多用三次。

把每种长方体的6种状态都枚举(长宽互换算两种,便于后面的排序),将其按先 x 后 y 排序(先 y 后 x 其实也一样。)

显然最优序列是排序后序列的一个子序列,而且是最长上升子序列。

此处上升的定义是 x 和 y 都要严格大于。

方程:dp[i] = h[i] + max(dp[j]) , j < i 且 i 可以放在 j 上。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 35 * 6;
int n, vcnt;

typedef struct Blk {
    int x, y, h;
}Blk;

Blk blk[maxn];
int dp[maxn];

void init()
{
    vcnt = 0;
    memset(dp, -1, sizeof(dp));
}

bool cmp(Blk a, Blk b)
{
    if(a.x == b.x) return a.y > b.y;
    else return a.x > b.x;
}

void addv(int a, int b, int c)
{
    blk[vcnt].x = a;
    blk[vcnt].y = b;
    blk[vcnt].h = c;
    vcnt++;
}

bool check(int i, int j)
{
    return (blk[i].x > blk[j].x && blk[i].y > blk[j].y);
}

int main()
{
    int ca = 1;
    while(scanf("%d", &n) && n) {
        int a, b, c;
        init();
        for(int i = 0; i < n; i++) {
            scanf("%d%d%d", &a, &b, &c);
            addv(a, b, c);
            addv(b, a, c);
            addv(a, c, b);
            addv(c, a, b);
            addv(b, c, a);
            addv(c, b, a);
        }
        sort(blk, blk + vcnt, cmp);
        for(int i = 0; i < vcnt; i++) {
            dp[i] = 0;
            for(int j = 0; j < i; j++) {
                if(check(j, i))
                    dp[i] = max(dp[j], dp[i]);
            }
            dp[i] += blk[i].h;
        }
        int ans = 0;
        for(int i = 0; i < vcnt; i++)
            ans = max(ans, dp[i]);
         printf("Case %d: maximum height = %d\n", ca++, ans);
    }

    return 0;
}

顺便附一下 TLE 的 DAG 动态规划代码。。。。。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 110 * 3;
int mat[maxn][maxn];
int x[maxn], y[maxn], h[maxn];
int outd[maxn];
bool done[maxn];
int n, vcnt;

void init()
{
    memset(mat, -1, sizeof(mat));
    memset(outd, 0, sizeof(outd));
    memset(done, false, sizeof(done));
    vcnt = 0;
}

void adde(int a, int b)
{
    mat[a][b] = h[b];
    outd[a]++;
}

void addv(int a, int b, int c)
{
    x[vcnt] = a;
    y[vcnt] = b;
    h[vcnt] = c;
    for(int i = 0; i < vcnt; i++) {
        int s1 = x[i] - a, s2 = y[i] - b;
        int s3 = x[i] - b, s4 = y[i] - a;
        if(s1 * s2 > 0 || s3 * s4 > 0) {
            if(s1 > 0 || s3 > 0)
                adde(i, vcnt);
            else if(s1 < 0 || s3 < 0)
                adde(vcnt, i);
        }
    }
    vcnt++;
}

//int dpa[maxn];
//
//int dp(int cur)
//{
//    if(dpa[cur] != -1) return dpa[cur];
//    int ret = 0;
//    for(int i = first[cur]; i != -1; i = next[i])
//        ret = max(ret, wt[i] + dp(to[i]));
//    return dpa[cur] = ret;
//}
int dp[maxn];

int main()
{
    int ca = 1;
    while(~scanf("%d", &n) && n) {
        init();
        for(int i = 0; i < n; i++) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            addv(a, b, c);
            addv(a, c, b);
            addv(b, c, a);
        }
        int ans = 0, cnt = 0;
//        memset(dpa, -1 ,sizeof(dpa));
        while(cnt < vcnt) {
            for(int i = 0; i < vcnt; i++) {
                if(outd[i] == 0 && !done[i]) {
                    dp[i] = 0;
                    for(int j = 0; j < vcnt; j++) {
                        if(mat[i][j] > 0)
                            dp[i] = max(dp[i], mat[i][j] + dp[j]);
                    }
                    for(int j = 0; j < vcnt; j++) {
                        if(mat[j][i] > 0)
                            outd[j]--;
                    }
                    done[i] = 1;
                    cnt++;
                }
            }
        }
        for(int i = 0; i < vcnt; i++)
            ans = max(ans, h[i] + dp[i]);
        printf("Case %d: maximum height = %d\n", ca++, ans);
    }

    return 0;
}

STACK_OVERFLOW 的递归版本。。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn = 110 * 3, maxe = 130000;
int x[maxn], y[maxn], h[maxn];
int fr[maxe], to[maxe], wt[maxe];
int first[maxn], next[maxe];
int n, ecnt, vcnt;

void init()
{
    memset(first, -1, sizeof(first));
    memset(next, -1, sizeof(next));
    ecnt = vcnt = 0;
}

void adde(int a, int b)
{
    fr[ecnt] = a;
    to[ecnt] = b;
    wt[ecnt] = h[b];
    next[ecnt] = first[a];
    first[a] = ecnt;
    ecnt++;
}

void addv(int a, int b, int c)
{
    x[vcnt] = a;
    y[vcnt] = b;
    h[vcnt] = c;
    for(int i = 0; i < vcnt; i++) {
        int s1 = x[i] - a, s2 = y[i] - b;
        int s3 = x[i] - b, s4 = y[i] - a;
        if(s1 * s2 > 0 || s3 * s4 > 0) {
            if(s1 > 0 || s3 > 0)
                adde(i, vcnt);
            else if(s1 < 0 || s3 < 0)
                adde(vcnt, i);
        }
    }
    vcnt++;
}

int dpa[maxn];

int dp(int cur)
{
    if(dpa[cur] != -1) return dpa[cur];
    int ret = 0;
    for(int i = first[cur]; i != -1; i = next[i])
        ret = max(ret, wt[i] + dp(to[i]));
    return dpa[cur] = ret;
}

int main()
{
    int ca = 1;
    while(~scanf("%d", &n) && n) {
        init();
        for(int i = 0; i < n; i++) {
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            addv(a, b, c);
            addv(a, c, b);
            addv(b, c, a);
        }
        int ans = 0;
        memset(dpa, -1 ,sizeof(dpa));
        for(int i = 0; i < vcnt; i++)
            ans = max(ans, h[i] + dp(i));
        printf("Case %d: maximum height = %d\n", ca, ans);
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值