版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}