/*
* 思路:
* 類似於最長下降子序列,由於可以自定義排列順序,所以肯定長和寬更大的排在前面更優,這裏採用了貪心的思想。
* dp[i]定義:以第i塊磚爲最後添加的一塊磚的最大高度。
* 分析狀態轉移方程:
* 1:第i塊磚自己作爲第一塊磚:nodes[i].h
* 2:第i塊磚放其他磚的後面,這裏由於不確頂放入哪個磚更優,所以要查找:dp[k],1 <= k < i,再加上
* nodes[i].h。
* 狀態轉移方程:
* dp[i] = max(nodes[i].h,
* dp[k] + nodes[i].h (1 <= k < i && nodes[i].l < nodes[k].l && nodes[i].w < nodes[k].w))
* 答案就在 max{ dp[i] (1 <= i <= n) }
*
* 技巧:
* 由於不確定磚的長寬高,所以暴力枚舉六種情況,相當於把每給的一組條件分成六種磚。這樣就相當於確定了磚的
* 長寬高。
*
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 30 + 10;
struct node{
ll l, w, h;
bool operator < (node cur)const {
if(l == cur.l)return w > cur.w;
return l > cur.l;
}
}nodes[N << 3];
ll n;
ll dp[N << 3];
inline void solve(ll m){
sort(nodes, nodes + m);
dp[0] = nodes[0].h;
ll maxn = dp[0];
for(ll i = 1; i < m; ++i){
ll upl = nodes[i].l, upw = nodes[i].w, uph = nodes[i].h;
dp[i] = nodes[i].h;
for(ll j = 0; j < i; ++j){
ll downl = nodes[j].l, downw = nodes[j].w, downh = nodes[j].h;
if(downl > upl && downw > upw)dp[i] = max(dp[i], dp[j] + uph);
}
maxn = max(maxn, dp[i]);
}
printf("%lld\n", maxn);
}
int main(){
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
ll cas = 1;
while(~scanf("%lld", &n) && n){
ll m = 0;
for(ll i = 0; i < n; ++i){
ll l, w, h;
scanf("%lld%lld%lld", &l, &w, &h);
nodes[m].l = l, nodes[m].w = w, nodes[m++].h = h;
nodes[m].l = l, nodes[m].w = h, nodes[m++].h = w;
nodes[m].l = w, nodes[m].w = l, nodes[m++].h = h;
nodes[m].l = w, nodes[m].w = h, nodes[m++].h = l;
nodes[m].l = h, nodes[m].w = w, nodes[m++].h = l;
nodes[m].l = h, nodes[m].w = l, nodes[m++].h = w;
}
printf("Case %lld: maximum height = ", cas++);
solve(m);
}
return 0;
}