The Tower of Babylon UVA - 437

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

思路:在任何时候,只有顶面的尺寸会影响到后续决策,因此可以用二元组(a,b)来表示“顶面尺寸为a*b这个状态”。因为每次增加一个立方体以后顶面的长和宽都会严格减小,所以这个图是DAG,可以套用DAG算法。

落实到程序时会遇到一个问题,不能直接用d(a,b)表示状态值,因为a和b可能会很大。可以用(idx,k)这个二元组来间接表达这个状态。其中idx为顶面立方体的序号,k是高的序号(假设输入时把每个立方体的3个维度从小到大排序,编号为0~2)。例如,若立方体3的大小为a * b * c(a <= b<= c),则状态(3,1)就表示这个立方体在顶面,且高是b(因此顶面大小为a * c).因此idx是0~n - 1的整数,k是0~2的整数

#include 
#define ll long long
#define ull unsigned long long
#define INF 0x3f3f3f3f
#define mod 1000000007;
using namespace std;
const int maxn = 32;
int cube[maxn][3];
int n,d[maxn][3];
//    freopen("in.txt","r",stdin);
//    freopen("out.txt","w",stdout);
void get(int *v1,int a,int b)
{
    int v = 0;
    for(int i = 0;i < 3;i++)
        if(i != b) v1[v++] = cube[a][i];
}
int dp(int a,int b)
{
    if(d[a][b] >= 0) return d[a][b];
    int ans = 0,v1[2],v2[2];
    get(v1,a,b);
    for(int i = 0;i < n;i++)
    {
        for(int j = 0;j < 3;j++)
        {
            get(v2,i,j);
            if(v1[0] > v2[0] && v1[1] > v2[1])
            {
                ans = max(ans,dp(i,j));
            }
        }
    }
    return d[a][b] = ans + cube[a][b];
}
int main()
{
    int kase = 1;
    while(scanf("%d",&n) && n)
    {
        int ans = 0;
        for(int i = 0;i < n;i++)
        {
            scanf("%d%d%d",&cube[i][0],&cube[i][1],&cube[i][2]);
            sort(cube[i],cube[i] + 3);
        }
        memset(d,-1,sizeof(d));
        for(int i = 0;i < n;i++)
        {
            for(int j = 0;j < 2;j++)
            {
                ans = max(ans,dp(i,j));
            }
        }
        printf("Case %d: maximum height = %d\n",kase++,ans);
    }
    return 0;
}

 

你可能感兴趣的:(紫书刷题)