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

#define rep(i,x,y) for(int i=(x);i<(y);++i)
#define debug(x) #x << "=" << (x)

#ifdef DEBUG
#define _GLIBCXX_DEBUG
#define print(x) std::cerr << debug(x) << " (L:" << __LINE__ << ")" << std::endl
#else
#define print(x)
#endif

const int inf=1e9;
const int64_t inf64=1e18;
const double eps=1e-9;

template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec){
    os << "[";
    for (const auto &v : vec) {
    	os << v << ",";
    }
    os << "]";
    return os;
}

using i64=int64_t;

template<class flow_type,class cost_type> struct min_cost_flow{
    struct edge{
        int to,from,rev;
        flow_type cap;
        cost_type cost;
        edge(int to,int from,int rev,flow_type cap,cost_type cost):
            to(to),from(from),rev(rev),cap(cap),cost(cost){}
    };
    const int size=0;
    vector<vector<edge>> graph;
    min_cost_flow(int size_):size(size_),graph(size_){}
    void add_edge(int from,int to,flow_type cap,cost_type cost){
        graph[from].push_back(edge(to,from,int(graph[to].size()),cap,cost));
        graph[to].push_back(edge(from,to,int(graph[from].size()-1),0,-cost));
    }
    cost_type min_path(int s,int t){
        const cost_type inf=numeric_limits<cost_type>::max();
        vector<cost_type> dist(size,inf);
        vector<edge*> route(size);
        queue<int> que;
        vector<bool> inq(size);
        dist[s]=0;
        que.push(s);
        inq[s]=true;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            inq[u]=false;
            for(edge &e:graph[u]){
                if(e.cap==0) continue;
                int v=e.to;
                if(dist[v]>dist[u]+e.cost){
                    dist[v]=dist[u]+e.cost;
                    route[v]=&e;
                    if(!inq[v]){
                        que.push(v);
                        inq[v]=true;
                    }
                }
            }
        }

        if(dist[t]==inf) return inf;
        flow_type flow=numeric_limits<flow_type>::max();
        {
            int v=t;
            while(v!=s){
                edge &e=*route[v];
                //e.cap-=1;
                //graph[e.to][e.rev].cap+=1;
                //c+=e.cost;
                flow=min(flow,e.cap);
                v=e.from;
            }
        }
        cost_type c=0;
        {
            int v=t;
            while(v!=s){
                edge &e=*route[v];
                e.cap-=flow;
                graph[e.to][e.rev].cap+=flow;
                c+=e.cost*flow;
                v=e.from;
            }
        }
        return dist[t];
    }
    //??????????????´??????numeric_limits<cost_type>::max()??????????????¨?????¨???
    cost_type calc_min_cost_flow(int s,int t,flow_type flow){
        cost_type total_cost=0;
        for(flow_type i=0; i<flow; ++i){
            cost_type c=min_path(s,t);
            if(c==numeric_limits<cost_type>::max()) return c;
            total_cost+=c;
        }
        return total_cost;
    }
};

void solve(int N){
    vector<vector<i64>> xyz(N,vector<i64>(3));
    rep(i,0,N) rep(j,0,3) cin >> xyz[i][j];

    auto ok=[&](int i,int j){
        bool res=false;
        vector<int> v={0,1,2};
        do{
            bool f=true;
            rep(k,0,3) if(xyz[i][v[k]]<=xyz[j][k]){
                f=false;
                break;
            }
            res|=f;
        }while(next_permutation(v.begin(),v.end()));
        return res;
    };

    min_cost_flow<i64,i64> mcf(2*N+2);
    const int s=2*N,t=2*N+1;
    rep(i,0,N){
        mcf.add_edge(s,i,1,0);
        mcf.add_edge(i+N,t,1,0);
        mcf.add_edge(i,t,1,0);
    }

    rep(i,0,N){
        rep(j,0,N){
            if(ok(i,j)) mcf.add_edge(i,j+N,1,-xyz[j][0]*xyz[j][1]*xyz[j][2]);
        }
    }

    i64 ans=0;
    rep(i,0,N) ans+=xyz[i][0]*xyz[i][1]*xyz[i][2];
    ans+=mcf.calc_min_cost_flow(s,t,N);
    cout << ans << endl;
}

int main(){
    std::cin.tie(0);
    std::ios::sync_with_stdio(false);
    cout.setf(ios::fixed);
    cout.precision(16);
    for(;;){
        int N;
        cin >> N;
        if(!N) break;
        solve(N);
    }
    return 0;
}

Measured memory_bytes: 3300