#include <iostream>
#include <assert.h> 
#include <tuple>
#include <vector>
#include <algorithm>
using namespace std;
typedef tuple<int,int,int> T;
typedef vector<vector<int>> Graph;

bool putin(T &A, T &B){//AがBに入るか
    int Ax,Ay,Az,Bx,By,Bz;
    tie(Ax,Ay,Az)=A;
    tie(Bx,By,Bz)=B;
    if(Ax<Bx&&Ay<By&&Az<Bz) return true;
    if(Ax<Bx&&Ay<Bz&&Az<By) return true;
    if(Ax<By&&Ay<Bx&&Az<Bz) return true;
    if(Ax<By&&Ay<Bz&&Az<Bx) return true;
    if(Ax<Bz&&Ay<Bx&&Az<By) return true;
    if(Ax<Bz&&Ay<By&&Az<Bx) return true;
    return false;
}
Graph G(1000);
int memo[1000];

int dfs(int i){
    if(!memo[i]){
        memo[i]=1;
        for(auto to:G[i]) memo[i]=max(memo[i],dfs(to)+1);
    }
    return memo[i];
}

int main(){
    int N;
    cin>>N;
    assert(1<=N&&N<=1000);
    vector<T> B;
    for(int i=0;i<N;i++){
        int X,Y,Z;
        cin>>X>>Y>>Z;
        assert(1<=X&&X<100000000);
        assert(1<=Y&&Y<100000000);
        assert(1<=Z&&Z<100000000);
        B.emplace_back(X,Y,Z);
    }
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(putin(B[i],B[j])) G[i].push_back(j);
        }
    }
    int ans = 0;
    for(int i=0;i<N;i++) ans = max(ans, dfs(i));
    cout<<ans<<endl;
}