#include <bits/stdc++.h>
using namespace std;
using ll = long long;
template <class T> using vec = vector<T>;
template <class T> using vvec = vector<vec<T>>;

using P = pair<ll,ll>;
const ll inf = 1e14;

class min_cost_flow{
private:
    int N;
    struct edge{int to; ll cap,cost; int rev; bool is_rev;};
    vector<vector<edge>> G;
    vector<ll> h,dist,prevv,preve;
public:
    min_cost_flow(int n){
        N = n;
        G = vector<vector<edge>>(N);
        h = dist = prevv = preve = vector<ll>(N,0);
    }
    void add_edge(int from,int to,ll cap,ll cost){
        G[from].push_back((edge){to,cap,cost,(int) G[to].size(),false});
        G[to].push_back((edge){from,0,-cost,(int) G[from].size()-1,true});
    }
    ll answer(int s,int t,ll f){
        ll res = 0;
        fill(h.begin(),h.end(),0);
        while(f>0){
            priority_queue<P,vector<P>,greater<P>> Q;
            fill(dist.begin(),dist.end(),inf);
            dist[s] = 0;
            Q.push(P(0,s));
            while(!Q.empty()){
                P p = Q.top(); Q.pop();
                int v = p.second;
                if(dist[v]<p.first) continue;
                for(int i=0;i<G[v].size();i++){
                    edge &e = G[v][i];
                    if(e.cap>0 && dist[e.to]>dist[v]+e.cost+h[v]-h[e.to]){
                        dist[e.to] = dist[v]+e.cost+h[v]-h[e.to];
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        Q.push(P(dist[e.to],e.to));
                    }
                }
            }
            if(dist[t]==inf) return -1;
            for(int v=0;v<N;v++) h[v] += dist[v];
            ll d = f;
            for(int v=t;v!=s; v=prevv[v]){
                d = min(d,G[prevv[v]][preve[v]].cap);
            }
            f -= d;
            res += d*h[t];
            for(int v=t;v!=s;v=prevv[v]){
                edge &e = G[prevv[v]][preve[v]];
                e.cap -= d;
                G[v][e.rev].cap += d;
            }
        }
        return res;
    }
};

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N;
    while(cin >> N && N){
        vec<int> X(N),Y(N),Z(N);
        int ans = 0;
        for(int i=0;i<N;i++){
            cin >> X[i] >> Y[i] >> Z[i];
            ans += X[i]*Y[i]*Z[i];
        }
        //i->j?
        auto in = [&](int i,int j){
            vvec<int> v(2);
            v[0].push_back(X[i]);
            v[0].push_back(Y[i]);
            v[0].push_back(Z[i]);
            v[1].push_back(X[j]);
            v[1].push_back(Y[j]);
            v[1].push_back(Z[j]);
            sort(v[0].begin(),v[0].end());
            sort(v[1].begin(),v[1].end());
            bool ok = true;
            for(int i=0;i<3;i++) ok &= v[0][i]>v[1][i];
            return ok;
        };
        int s = 2*N,t = 2*N+1;
        min_cost_flow flow(2*N+2);

        auto id = [&](int i,int f){
            return i+f*N;
        };

        for(int i=0;i<N;i++){
            flow.add_edge(s,id(i,0),1,0);
            flow.add_edge(id(i,1),t,1,0);
            flow.add_edge(id(i,0),id(i,1),1,0);
            for(int j=0;j<N;j++) if(in(i,j)){
                flow.add_edge(id(i,1),id(j,0),1,-X[j]*Y[j]*Z[j]);
            }
        }
        flow.add_edge(s,t,N,0);
        int a = flow.answer(s,t,N);
//        cerr << a << "\n";
        cout << ans+a << "\n";
    }
}



Measured memory_bytes: 3380