Great performance strategy

Taro, an examinee, participated in an N-day study camp. In this training camp, M subjects are tested every day, and after the training camp, a report card with all the test scores is distributed. The report card consists of N sheets of paper, and on the i-th sheet, only the subject names and scores of the tests of all M subjects on the i-day are printed.

Taro noticed that the date was not written on the report card, and decided to add some work before giving the report card to his mother. By rearranging the order of the papers in the report card and writing the page numbers in order from the first sheet to make a booklet, a "fake report card" was created. Taro's purpose is to maximize the number of subjects whose test scores are monotonously increasing with respect to page numbers in the "False Report Card".

When Taro makes a "false grade report", find the maximum number of subjects whose test scores are monotonously increasing with respect to the page number.

However, the N-day test score is a broad monotonous increase with respect to the page number. For 1 ≤ i <N, the score on the i + 1 sheet is the score on the i-th sheet. It means that it is the above.

Input

The input consists of 50 or less datasets. Each dataset is represented in the following format.

> N M a11 ... a1M ... aN1 ... aNM

The first line gives the number of days N and the number of subjects M for the study camp. N is an integer between 1 and 103, and M is an integer between 1 and 40.

Taro's score is given to the following N lines. Each line consists of M integers, where aij is the score of Taro-kun's subject j on day i, and aij is an integer between 0 and 103.

The end of the input is represented by a line of two zeros.

Output

For each dataset, output the maximum number of subjects whose test scores are monotonously increasing with respect to the page number on one line.

Sample Input


3 3
one two Three
2 1 3
3 3 3
8 5
3 3 4 3 4
2 1 2 3 2
7 9 7 8 7
3 4 3 3 4
1 2 2 3 2
4 5 6 5 6
7 9 7 7 8
4 5 5 6 6
5 5
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
5 9
1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
0 0


Output for the Sample Input


2
3
1
9






Example

Input

3 3
1 2 3
2 1 3
3 3 3
8 5
3 3 4 3 4
2 1 2 3 2
7 9 7 8 7
3 4 3 3 4
1 2 2 3 2
4 5 6 5 6
7 9 7 7 8
4 5 5 6 6
5 5
1 2 3 4 5
2 3 4 5 1
3 4 5 1 2
4 5 1 2 3
5 1 2 3 4
5 9
1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2
3 3 3 3 3 3 3 3 3
4 4 4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
0 0


Output

2
3
1
9

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

template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b)a=b;};
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b)a=b;};


struct SCC{
  vector<vector<int> > G, R, T, C;
  vector<int> vs, used, blg;

  SCC(){}
  SCC(int n):G(n), R(n), used(n), blg(n){}

  void add_edge(int u, int v){
    G[u].emplace_back(v);
    R[v].emplace_back(u);
  }

  void dfs(int v){
    used[v] = 1;
    for(int u:G[v])
      if(!used[u]) dfs(u);
    vs.emplace_back(v);
  }

  void rdfs(int v, int k){
    used[v] = 1;
    blg[v] = k;
    C[k].emplace_back(v);
    for(int u:R[v])
      if(!used[u]) rdfs(u, k);
  }

  int build(){
    int n =G.size();
    for(int v=0;v<n;v++)
      if(!used[v]) dfs(v);

    fill(used.begin(), used.end(), 0);

    int k = 0;
    for(int i=n-1;i>=0;i--){
      if(!used[vs[i]]){
        T.emplace_back();
        C.emplace_back();
        rdfs(vs[i], k++);
      }
    }

    for(int v=0;v<n;v++)
      for(int u:G[v])
        if(blg[v] != blg[u])
          T[blg[v]].push_back(blg[u]);

    for(int i=0;i<k;i++){
      sort(T[i].begin(), T[i].end());
      T[i].erase(unique(T[i].begin(), T[i].end()), T[i].end());
    }
    return k;
  }
  int operator[](int k) const{return blg[k];}
};


struct IndependentSet{
  int n;
  vector<vector<int> > G;
  IndependentSet(int n):n(n), G(n){}

  void add_edge(int u, int v){
    G[u].emplace_back(v);
    G[v].emplace_back(u);
  }

  int build(){
    vector<int> deg(n, 0);
    for(int i=0;i<n;i++) deg[i] = G[i].size();

    int res = 0, cnt = 0, alive = n;
    vector<int> used(n, 0), dead(n, 0);

    function<void(void)> dfs = [&](){
      if(cnt + alive <= res) return;
      int v = -1;

      for(int i=0;i<n;i++){
        if(used[i] || dead[i] ) continue;
        if(deg[i] <= 1){
          v = i;
          break;
        }
        if(v < 0 || deg[v] < deg[i]) v = i;
      }

      if(v < 0) return;

      if(deg[v] != 1){
        dead[v] = 1;
        alive--;
        for(int u:G[v]) deg[u]--;
        dfs();

        dead[v] = 0;
        alive++;
        for(int u:G[v]) deg[u]++;
      }

      {
        used[v] = 1;
        alive--;
        for(int u:G[v])
          if(0 == dead[u]++) alive -= !used[u];
        
        cnt++;
        chmax(res, cnt);

        dfs();
        used[v] = 0;
        alive++;
        for(int u:G[v])
          if(--dead[u] == 0) alive += !used[u];
        cnt--;
                               
      }
    };

    dfs();
    return res;
  }

};
signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n,m;
  while(cin>>n>>m,n){
    vector< vector<int> > as(n,vector<int>(m));
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
        cin>>as[i][j];
    
    IndependentSet G(m);
    for(int a=0;a<m;a++){
      for(int b=0;b<a;b++){
        int ng=0;
        for(int i=0;i<n;i++){
          for(int j=0;j<i;j++){
            if(as[i][a]==as[j][a]) continue;
            if(as[i][b]==as[j][b]) continue;
            if((as[i][a]>as[j][a])^(as[i][b]>as[j][b])) ng=1;
            if(ng) break;
          }
          if(ng) break;
        }
        
        if(ng) G.add_edge(a,b);        
      }
    }

    cout<<G.build()<<endl;
  }
  
  return 0;
}

