设 \(f_i\) 表示对于前 \(i\) 组,必定选第 \(i\) 个积木的最大可能高度,\(f_i=\max f_k+z_{i}\) 然后一开始往数组中扔进 \(6\) 个不同面的积木,然后拍个序去除后效性即可(虽然本来就没有后效性)。
注意:位于下面的积木的长和宽必须严格大于位于上面的积木的长和宽。每种积木的供应数量无限多。自由决定积木的哪个面作为底面,以及积木的具体摆放朝向。
// #define FILE_INPUT
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;#define rep(i, a, b) for (int i = a, END##i = b; i <= END##i; i++)
#define per(i, a, b) for (int i = a, END##i = b; i >= END##i; i--)void Init();
void Solve();signed main() {cin.sync_with_stdio(0);cin.tie(0), cout.tie(0);#ifdef FILE_INPUTfreopen("input.in", "r", stdin);#endifint T = 1;// cin >> T;while (T--) {Init();Solve();}return 0;
}using LL = long long;
using ULL = unsigned long long;const int Mod = 1e9 + 7;
const int Inf = 0x3f3f3f3f;
const LL InfLL = 0x3f3f3f3f3f3f3f3f;const int N = 1e6 + 10;
int n, f[N], cnt;
struct Node {int x, y, z;Node() {};Node(int x, int y, int z) : x(x), y(y), z(z) {};bool operator< (const Node& b) const {return x == b.x ? y < b.y : x < b.x;}
}a[N];void Init() {
}int cases;void Solve() {while (cin >> n, n) {cnt = 0;rep(i, 1, n) {int x, y, z; cin >> x >> y >> z;a[++cnt] = Node(x, y, z);a[++cnt] = Node(x, z, y);a[++cnt] = Node(y, x, z);a[++cnt] = Node(y, z, x);a[++cnt] = Node(z, x, y);a[++cnt] = Node(z, y, x);}sort(a + 1, a + cnt + 1);int ans = 0;rep(i, 1, cnt) {f[i] = a[i].z;rep(j, 1, i - 1) {if (a[i].x == a[j].x || a[i].y <= a[j].y) continue;f[i] = max(f[i], f[j] + a[i].z);}ans = max(ans, f[i]);}cout << "Case " << ++cases << ": maximum height = " << ans << "\n";}
}