HDOJ 1069 Monkey and Banana(LIS)

来源:互联网 发布:软件测试自学教程视频 编辑:程序博客网 时间:2024/05/05 21:48

题意,给出 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
原创粉丝点击