#include<bits/stdc++.h>
using namespace std;
using Int = long long;

const Int inf = 1LL<<55;

struct edge {
  Int to, cap, cost, rev;
  edge(){}
  edge(Int to, Int cap, Int cost, Int rev)
    :to(to), cap(cap), cost(cost), rev(rev){}
};

typedef pair<Int, Int> Pi;

struct PrimalDual {
  vector< vector<edge> > graph;
  vector<Int> mincost, h, prevv, preve;
  PrimalDual(Int V):graph(V), mincost(V), h(V), prevv(V), preve(V){}
  void add_edge(Int from, Int to, Int cap, Int cost) {
    //cout<<from<<" "<<to<<" "<<cap<<" "<<cost<<endl;
    graph[from].emplace_back(to, cap, cost, (Int)graph[to].size());
    graph[to].emplace_back(from, 0, -cost, (Int)graph[from].size()-1);
  }
  Int min_cost_flow(Int s, Int t, Int f) {
    Int res = 0;
    fill(h.begin(), h.end(), 0);
    fill(prevv.begin(), prevv.end(), -1);
    fill(preve.begin(), preve.end(), -1);

    while(f > 0) {
      priority_queue<Pi, vector<Pi>, greater<Pi> > que;
      fill(mincost.begin(), mincost.end(), inf);
      mincost[s] = 0;
      que.emplace(0, s);
      while(!que.empty()) {
        Pi p = que.top(); que.pop();
        Int v = p.second;
        if(mincost[v] < p.first) continue;
        for(Int i = 0; i < (Int)graph[v].size(); i++) {
          edge& e = graph[v][i];          
          Int dual_cost = mincost[v] + e.cost + h[v] - h[e.to];
          //cout<<dual_cost<<endl;
          if(e.cap > 0 && dual_cost < mincost[e.to]) {
            mincost[e.to] = dual_cost;
            prevv[e.to] = v; preve[e.to] = i;
            que.emplace(dual_cost, e.to);
          }
        }
      }

      if(mincost[t] == inf) return inf;
      for(Int v = 0; v < (Int)graph.size(); v++) h[v] += mincost[v];
      Int d = f;
      for(Int v = t; v != s; v = prevv[v]) {
        d = min(d, graph[prevv[v]][preve[v]].cap);
      }
      f -= d;
      res += d*h[t];
      //cout<<res<<" "<<d<<" "<<h[t]<<endl;
      for(Int v = t; v != s; v = prevv[v]) {
        edge& e = graph[prevv[v]][preve[v]];
        e.cap -= d;
        graph[v][e.rev].cap += d;
      }
    }
    return res;
  }
};

struct doll{
  Int x,y,z;
  doll(){}
  doll(Int x,Int y,Int z):x(x),y(y),z(z){}
  Int getVol() {
    return x*y*z;
  }
};

Int in(doll a,doll b){
  for(Int k=0;k<6;k++){
    if(k==1||k==3||k==5) swap(a.x,a.y);
    if(k==2||k==4) swap(a.x,a.z);
    if(b.x<a.x&&b.y<a.y&&b.z<a.z) return true;
  }
  return false;
}

signed main(){
  Int n;
  while(cin >> n, n) {
    vector<doll> D(n);
    Int ans = 0;
    for(Int i = 0; i < n; i++) {
      cin >> D[i].x >> D[i].y >> D[i].z;
      ans += D[i].getVol();
    }
    Int s = n*2, t = s+1, V = t+1;
    PrimalDual graph(V);
    for(Int i = 0; i < n; i++) {
      graph.add_edge(s, i, 1, 0);
    }
    for(Int i = 0; i < n; i++) {
      graph.add_edge(i, t, 1, 0); 
    }
    for(Int i = 0; i < n; i++) {
      for(Int j = 0; j < n; j++) {
        if(i == j) continue;
        if(in(D[i], D[j])) {
          //cout<<"in "<<i<<" "<<j<<endl;
          graph.add_edge(i, n+j, 1, -D[j].getVol());
        }
      }
    }
    //cout << ans << endl;
    for(Int i = 0; i < n; i++) {
      graph.add_edge(n+i, t, 1, 0);
    }
    //cout<<n<<endl;
    Int tmp = graph.min_cost_flow(s, t, n);
    assert(tmp != inf);
    cout << ans + tmp << endl;
  }
  return 0;
}



Measured memory_bytes: 3220