UVA 437 The Tower of Babylon 题解(DAG上的DP+神奇的数组索引设置)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Q1410136042/article/details/80445985

题目传送门:UVA 437 巴比伦塔

题意:有n(n≤30)种立方体,每种都有无穷多个。要求选一些立方体摞成一根尽量高的柱子(可以自行选择哪一条边作为高),使得每个立方体的底面长宽分别严格小于它下方立方体的底面长宽。

分析:这个一看就是DAG上的最长路,瞬间写出状态转移方程:

以dp[i][j]表示当前立方体长款分别为i和j,往它上面堆立方体,使其满足条件的最大高度

则dp[i][j] = max(dp[x][y]+h),x,y,h是某个立方体的长宽高并且满足x<i,y<j

这样写起来很简单啊,问题是题目并没说长宽范围,二维的dp数组不知道该开多大。。。

既然是二维的,那数字应该不是很大,就设置为1000好了,然后:


额,尴尬,好吧,设置成10000吧,数据再大就没法做了啊,于是~~


嗯,一下子AC不了了啊~

回头再看一下算法思路,dp[i][j]两个索引,一个表示长,一个表示宽,它俩都是一个立方体里的,换句话说,i和j存在的意思是为了确定当前是哪个立方体在下面,并且要确定底面——立方体可以直接用立方体的序号来表示,这一维只有30的大小。然后就是确定底面了,换句话说,确定立方体的哪条边作为高~立方体有三条边,可以用一个数组表示,也就是每条边也对应着一个序号——这就出来了,可以像用序号确定立方体一样,用序号来确定高,也就是确定底边——嗯,dp数组的第二维出来了,这一维只有3的大小。

这种设置dp索引的方式很奇妙啊,只有30个立方体,如果用之前的方式来表示dp数组,即使不越界,也会由于数据过于离散而造成大量空间浪费——第二种数组设置方式巧妙地回避了数组越界和空间浪费的问题了,贼赞呢~

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#include<iomanip>
#include<algorithm>
#include<string>
#include<cstring>
#define LL long long
#define DEBUG printf("DEBUG\n")
#define FOR(i, s, n) for(int i = s; i < n; ++ i)
#define For(i, s, n) for(int i = s; i > n; -- i)

const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 1e5;
using namespace std;
struct cube
{
    int a[3];
}C[31];
int DP[31][3];
int n, _case = 1;
int dp(int CubeId, int HId)
{
    int& ans = DP[CubeId][HId];
    if(ans)    return ans;
    int x, y;
    if(HId == 0)
        x = C[CubeId].a[1], y = C[CubeId].a[2];
    else if(HId == 1)
        x = C[CubeId].a[0], y = C[CubeId].a[2];
    else
        x = C[CubeId].a[0], y = C[CubeId].a[1];
    FOR(i, 1, n+1)
    {
        int& a = C[i].a[0], &b = C[i].a[1], &c = C[i].a[2];
        if(a < x && b < y || a < y && b < x)
            ans = max(ans, dp(i, 2)+c);
        if(b < x && c < y || b < y && c < x)
            ans = max(ans, dp(i, 0)+a);
        if(a < x && c < y || c < x && a < y)
            ans = max(ans, dp(i, 1)+b);
    }
    return ans;
}
int main()
{
    #ifdef AFei
    freopen("in.c", "r", stdin);
    #endif // AFei
    C[0].a[0] = C[0].a[1] = C[0].a[2] = INF;
    while(scanf("%d", &n), n)
    {
        memset(DP, 0, sizeof DP);
        FOR(i, 1, n+1)    scanf("%d%d%d", &C[i].a[0], &C[i].a[1], &C[i].a[2]);
        printf("Case %d: maximum height = %d\n", _case ++, dp(0, 0));
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/Q1410136042/article/details/80445985