题意
有 n 种长方体石块( x,y,z ),每种无限多,从中挑选一些石块组成一座塔,要求每个长方体石块的底面长宽严格小于它下方石块的底面长宽。每个石块可以任意选择一边作为高。求塔的最大高度。 n<=30 .
题解
每个长方体可以有6种形态,那么这 n 种长方体共有 6n 种形态,两种形态的长方体的底面长宽是一个二元关系,因此,这便转化为一个DAG图,和矩形嵌套类似。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200;
int dp[maxn];
int n, t, kcase;
struct rec{
int x, y, z;
void append(int x, int y, int z) { this->x = x, this->y = y, this->z = z; }
}r[maxn];
inline void build(int x, int y, int z)
{
r[t++].append(x, y, z);
r[t++].append(x, z, y);
r[t++].append(y, x, z);
r[t++].append(y, z, x);
r[t++].append(z, x, y);
r[t++].append(z, y, x);
}
int DP(int i)
{
int &ans = dp[i];
if(ans > 0) return ans;
ans = r[i].z;
for(int j = 0; j < t; ++j)
{
if(r[i].x < r[j].x && r[i].y < r[j].y) ans = max(ans, DP(j) + r[i].z);
}
return ans;
}
int main()
{
#ifdef LOCAL
fstream cin("data.in");
#endif
ios::sync_with_stdio(false);
while(cin >> n && n)
{
int x, y, z;
t = 0;
for(int i = 0; i < n; ++i)
{
cin >> x >> y >> z;
build(x, y, z);
}
memset(dp, 0, sizeof(dp));
int ans = 0;
for(int i = 0; i < t; ++i) ans = max(ans, DP(i));
printf("Case %d: maximum height = %d\n", ++kcase, ans);
}
return 0;
}
另,如果把所有长方体的底面按面积递增的顺序排序,原问题转化为最长上升子序列问题。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200;
int dp[maxn];
int n, t, kcase;
struct rec{
int x, y, z;
void append(int x, int y, int z) { this->x = x, this->y = y, this->z = z; }
}r[maxn];
inline void build(int x, int y, int z)
{
r[t++].append(x, y, z);
r[t++].append(x, z, y);
r[t++].append(y, x, z);
r[t++].append(y, z, x);
r[t++].append(z, x, y);
r[t++].append(z, y, x);
}
int cmp(const rec& a, const rec& b)
{
return a.x * a.y < b.x * b.y;
}
int main()
{
#ifdef LOCAL
fstream cin("data.in");
#endif
ios::sync_with_stdio(false);
while(cin >> n && n)
{
int x, y, z;
t = 0;
for(int i = 0; i < n; ++i)
{
cin >> x >> y >> z;
build(x, y, z);
}
sort(r, r + t, cmp);
memset(dp, 0, sizeof(dp));
int ans = 0;
for(int i = 0; i < t; ++i)
{
dp[i] = r[i].z;
for(int j = 0; j < i; ++j){
if(r[i].x > r[j].x && r[i].y > r[j].y)
dp[i] = max(dp[i], dp[j] + r[i].z);
ans = max(ans, dp[i]);
}
}
printf("Case %d: maximum height = %d\n", ++kcase, ans);
}
return 0;
}