The Tower of Babylon
紫书P269
有n种立方体,每种都有无穷多个。要求选一些立方体落成一根尽量高的柱子(可以自行选择哪一条边作为高),是的每个立方体的底面长款分别严格小于它下方立方体的底面长宽。
立方体可以旋转,所以一种立方体可以看成三个固定摆法的立方体,即为3*n种立方体中求最长路。
#include<iostream>
#include<algorithm>
#include<cstring>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxn = 34;
struct node
{
int a, b, h;
}block[maxn*3];
bool able[maxn*3][maxn*3];//i的k种方法能不能放在j的l种方法上
int n;
bool can_put(int x,int y)
{
if (block[x].a < block[y].a&&block[x].b < block[y].b)
return true;
if (block[x].b < block[y].a&&block[x].a < block[y].b)
return true;
return false;
}
int dp[maxn*3];//用第i个木块当顶的最大高度
int dfs(int x)
{
if (x == 0)
return 0;
if (dp[x] != 0)
return dp[x];
//int k = x / 3;//每种方块有无限个
//int self[3] = { k * 3 + 1,k * 3 + 2,k * 3 + 3 };
int temp = block[x].h;
for (int i = 1; i <= 3 * n; i++)
{
//if (i == self[0] || i == self[1] || i == self[2])
// continue;
if (able[x][i])
{
temp = max(temp, dfs(i) + block[x].h);
}
}
return dp[x] = temp;
}
int main()
{
int cnt = 1;
while (scanf("%d", &n)!=EOF)
{
if (n == 0)
return 0;
for (int i = 1; i <= n; i++)
{
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
block[3*i] = { x,y,z };
block[3*i-1] = { y,z,x };
block[3*i-2] = { x,z,y };
}
for (int i = 1; i <= 3 * n; i++)
{
for (int j = 1; j <= 3 * n; j++)
{
if (i == j)
continue;
able[i][j] = can_put(i, j);
}
}
int ans = 0;
mem(dp, 0);
for (int i = 1; i <= 3*n; i++)
{
ans = max(ans, dfs(i));
}
printf("Case %d: maximum height = %d\n", cnt++,ans);
}
}