Problem:
成績上昇大作戦

受験生の太郎君は N 日間の勉強合宿に参加した．
この合宿では毎日 M 科目のテストを行い，
合宿の終了後にはすべてのテストの点数が書かれた成績表が配られる．
成績表は N 枚の紙からなっており，i 枚目の紙には i 日目の全 M 科目のテストの科目名と点数のみが印刷されている．

成績表に日付が書かれていないことに気付いた太郎君は，お母さんに成績表を渡す前に細工を加えることにした．
成績表の紙の順番を並べ替え，さらに1枚目から順番にページ番号を書き込んで冊子にすることによって「偽りの成績表」を作ったのだ．
太郎君の目的は，「偽りの成績表」でテストの点数がページ番号に対して広義単調増加している科目の個数を最大化することである．

太郎君が「偽りの成績表」を作るとき，テストの点数がページ番号に対して広義単調増加である科目の個数の最大値を求めよ．

ただし，N 日間のテストの点数がページ番号に対して広義単調増加であるとは 1 ≤ i < N に対して i+1 枚目に記載されている点数が i 枚目に記載されている点数以上であることを意味する．

Input

入力は 50 個以下のデータセットからなる． 各データセットは次の形式で表される．

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

1行目には，勉強合宿の日数 N と科目数 M が与えられる．N は 1 以上 103 以下の整数で，M は 1 以上 40 以下の整数である．

続く N 行には太郎君の点数が与えられる．各行は M 個の整数からなっており aij は太郎君の i 日目の科目 j の点数であり，aij は 0 以上 103 以下の整数である．

入力の終わりは，2 つのゼロからなる行で表される．

Output

各データセットについて，テストの点数がページ番号に対して広義単調増加である科目の個数の最大値を 1 行に出力せよ．

Sample 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 for the Sample Input

2
3
1
9

Solution in C++ (judge verdict: Accepted)

#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 45

enum Type{
	UNDEFINED,
	TRUE,
	FALSE,
};

struct Info{
	Info(int arg_main_value,int arg_sub_value){
		main_value = arg_main_value;
		sub_value = arg_sub_value;
	}
	bool operator<(const struct Info &arg) const{

		if(main_value != arg.main_value){

			return main_value < arg.main_value;
		}else{

			return sub_value < arg.sub_value;
		}
	}

	int main_value,sub_value;
};

int N,M;
int table[1005][SIZE];
vector<int> G[SIZE];
vector<Info> info;
int ans;
Type type[SIZE];

void recursive(int node_id,int count){

	if(count+(M-node_id+1) <= ans)return;

	if(node_id == M){

		ans = max(ans,count);

		return;
	}

	if(type[node_id] != UNDEFINED){ //決定済

		recursive(node_id+1,count);
		return;
	}

	Type pre[SIZE];
	for(int i = 0; i < M; i++){
		pre[i] = type[i];
	}

	type[node_id] = FALSE;
	recursive(node_id+1,count);

	for(int i = 0; i < M; i++){

		type[i] = pre[i];
	}

	type[node_id] = TRUE;
	for(int i = 0; i < G[node_id].size(); i++){

		type[G[node_id][i]] = FALSE;
	}
	recursive(node_id+1,count+1);
}

void func(){

	info.clear();

	for(int i = 0; i < SIZE; i++){
		G[i].clear();
	}

	for(int i = 0; i < N; i++){
		for(int k = 0; k < M; k++){
			scanf("%d",&table[i][k]);
		}
	}

	//同時に昇順にできないペアを探す
	for(int i = 0; i < M-1; i++){
		for(int k = i+1; k < M; k++){

			info.clear();

			for(int a = 0; a < N; a++){

				info.push_back(Info(table[a][i],table[a][k]));
			}

			sort(info.begin(),info.end());

			bool FLG = true;

			for(int a = 0; a < N-1; a++){
				for(int b = a+1; b < N; b++){
					if(info[a].main_value < info[b].main_value && info[a].sub_value > info[b].sub_value){
						FLG = false;
						break;
					}
				}
				if(!FLG)break;
			}

			if(!FLG){

				G[i].push_back(k);
				G[k].push_back(i);
			}
		}
	}

	ans = 1;
	int first_count = 0;

	for(int i = 0; i < M; i++){

		if(G[i].size() > 0){
			type[i] = UNDEFINED;
		}else{
			type[i] = TRUE; //無条件採用
			first_count++;
		}
	}

	recursive(0,first_count);

	printf("%d\n",ans);
}

int main(){

	while(true){
		scanf("%d %d",&N,&M);
		if(N == 0 && M == 0)break;

		func();
	}

	return 0;
}