Problem:
Problem H:
Bingo
A Bingo game is played by one gamemaster and several players. At the beginning of a game,
each player is given a card with
M
×
M
numbers in a matrix (See Figure 10).
As the game proceeds, the gamemaster announces a series of numbers one by one. Each player
punches a hole in his card on the announced number, if any.
When at least one 'Bingo' is made on the card, the player wins and leaves the game. The 'Bingo'
means that all the
M
numbers in a line are punched vertically, horizontally or diagonally (See
Figure 11).
The gamemaster continues announcing numbers until all the players make a Bingo.
In the ordinary Bingo games, the gamemaster chooses numbers by a random process and has no
control on them. But in this problem the gamemaster knows all the cards at the beginning of
the game and controls the game by choosing the number sequence to be announced at his will.
Specifically, he controls the game to satisfy the following condition.
Card
i
makes a Bingo no later than Card
j
, for
i
<
j
. (*)
Figure 12 shows an example of how a game proceeds. The gamemaster cannot announce '5'
before '16', because Card
4
makes a Bingo before Card
2
and Card
3
, violating the condition (*).
Your job is to write a program which finds the minimum length of such sequence of numbers for
the given cards.
Input
The input consists of multiple datasets. The format of each dataset is as follows.
All data items are integers.
P
is the number of the cards, namely the number of the players.
M
is the number of rows and the number of columns of the matrix on each card.
N
k
ij
means the number written at the position (
i
,
j
) on the
k
-th card. If (
i
,
j
) ≠ (
p
,
q
), then
N
k
ij
≠
N
k
pq
. The parameters
P
,
M
, and
N
satisfy the conditions 2 ≤
P
≤ 4, 3 ≤
M
≤ 4, and 0 ≤
N
k
ij
≤ 99.
The end of the input is indicated by a line containing two zeros separated by a space. It is not
a dataset.
Output
For each dataset, output the minimum length of the sequence of numbers which satisfy the
condition (*). Output a zero if there are no such sequences. Output for each dataset must be
printed on a separate line.
Sample Input
4 3
10 25 11 20 6 2 1 15 23
5 21 3 12 23 17 7 26 2
8 18 4 22 13 27 16 5 11
19 9 24 2 11 5 14 28 16
4 3
12 13 20 24 28 32 15 16 17
12 13 21 25 29 33 16 17 18
12 13 22 26 30 34 17 18 15
12 13 23 27 31 35 18 15 16
4 3
11 12 13 14 15 16 17 18 19
21 22 23 24 25 26 27 28 29
31 32 33 34 35 36 37 38 39
41 42 43 44 45 46 47 48 49
4 4
2 6 9 21 15 23 17 31 33 12 25 4 8 24 13 36
22 18 27 26 35 28 3 7 11 20 38 16 5 32 14 29
26 7 16 29 27 3 38 14 18 28 20 32 22 35 11 5
36 13 24 8 4 25 12 33 31 17 23 15 21 9 6 2
0 0
Output for the Sample Input
5
4
12
0
For your convenience, sequences satisfying the condition (*) for the first three datasets are shown
below. There may be other sequences of the same length satisfying the condition, but no shorter.
11, 2, 23, 16, 5
15, 16, 17, 18
11, 12, 13, 21, 22, 23, 31, 32, 33, 41, 42, 43

Submitted solutions:

code_snippet: #include <iostream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;

const int maxn = 7, maxv = 107, maxt = 10007, maxnum = 100000000;
      int n, m, res, total;
      int has[maxv], cal[maxt];

vector<int> zz[maxt];

struct MAT
{
    int c[maxn][maxn];
    MAT() {}
    void output()
    {
        puts("/////////////////////////////////////////");
        for (int i = 1; i <= m ; i++)
        {
            for (int j = 1; j <= m; j++) printf("%d ", c[i][j]);
            puts("");
        }
    }
} mat[maxn];

int cc[maxv];

void FIND(int pos, int top)
{
    if (pos > n)
    {
        ++total;
        zz[total].clear();
        for (int i = 1; i <= top; i++) zz[total].push_back(cc[i]);
        map<int, int> Map;
        for (int i = 1; i <= top; i++) Map[cc[i]];
        cal[total] = Map.size();
        return;
    }
    for (int i = 1; i <= m; i++)
    {
        for (int j = 1; j <= m; j++) cc[top+j] = mat[pos].c[i][j]; 
        FIND(pos+1, top+m);
    }
    for (int j = 1; j <= m; j++)
    {
        for (int i = 1; i <= m; i++) cc[top+i] = mat[pos].c[i][j];
        FIND(pos+1, top+m);
    }
    for (int i = 1; i <= m; i++) cc[top+i] = mat[pos].c[i][i];
    FIND(pos+1, top+m);
    for (int i = 1; i <= m; i++) cc[top+i] = mat[pos].c[m-i+1][i];
    FIND(pos+1, top+m);
}

bool Bingo(MAT M)
{
    ////////////////////////////////////////////////
    for (int i = 1; i <= m; i++)
    {
        bool ok = true;
        for (int j = 1; j <= m; j++)
            if (has[M.c[i][j]] == 0) ok = false;
        if (ok) return true;
    }
    ////////////////////////////////////////////////
    for (int j = 1; j <= m; j++)
    {
        bool ok = true;
        for (int i = 1; i <= m; i++)
            if (has[M.c[i][j]] == 0) ok = false;
        if (ok) return true;
    }
    ////////////////////////////////////////////////
    bool ok = true;
    for (int i = 1; i <= m; i++)
        if (has[M.c[i][i]] == 0) ok = false;
    if (ok) return true;
    ////////////////////////////////////////////////
    ok = true;
    for (int i = 1; i <= m; i++)
        if (has[M.c[m-i+1][i]] == 0) ok = false;
    if (ok) return true;
    return false;
    ////////////////////////////////////////////////
}

bool BUG()
{
    int Tmax = 0, Tmin = n+1;
    for (int i = 1; i <= n; i++)
        if (Bingo(mat[i])) Tmax = max(Tmax, i);
        else               Tmin = min(Tmin, i);
    return Tmax > Tmin;
}

bool dfs(vector<int> &zz, int pos)
{
    if (pos == n) return true;
    for (int i = 0; i < m; i++)
    {
        bool ok = true;
        int x = zz[pos*m+i];
        for (int j = pos+1; j < n; j++)
        {
            bool bug = true;
            for (int k = 0; k < m; k++)
                if (zz[j*m+k] == x) bug = false;
            if (bug) ok = false;
        }
        if (ok)
        {
            for (int j = pos; j < n; j++)
                for (int k = 0; k < m; k++)
                    if (zz[j*m+k] != x) has[zz[j*m+k]]++;
            bool nice = true;
            for (int j = pos; j < n; j++)
                if (Bingo(mat[j+1])) nice = false;
            if (nice) return true;
            for (int j = pos; j < n; j++)
                for (int k = 0; k < m; k++)
                    if (zz[j*m+k] != x) has[zz[j*m+k]]--;
        }
    }
    for (int i = 0; i < m; i++)
    {
        has[zz[pos*m+i]]++;
        if (BUG()) return false;
    }
    return dfs(zz, pos+1);
}

void work()
{
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 1; k <= m; k++) scanf("%d", &mat[i].c[j][k]);
    total = 0;
    FIND(1, 0);
    int res = maxnum;
    for (int i = 1; i <= total; i++)
        if (cal[i] < res)
        {
            memset(has, 0, sizeof(has));
            if (dfs(zz[i], 0)) res = cal[i];
        }
    printf("%d\n", (res < maxnum)? res:0);
}

int main()
{
    while (scanf("%d%d", &n, &m) && n) work();
}
accuracy: 1
time_ms: 70
memory_kb: 4548
final_rank: 6

code_snippet: #include <iostream>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

struct pt {
   int c, x, y;
};

int c[4][4][4], N;
bool s[100];

int check(int card, int x, int y) {
	int i;

   for (i=0; i<N; i++) if (s[c[card][x][i]] == false) break;
	if (i == N) return x;

   for (i=0; i<N; i++) if (s[c[card][i][y]] == false) break;
	if (i == N) return N + y;

	if (x == y) {
	   for (i=0; i<N; i++) if (s[c[card][i][i]] == false) break;
		if (i == N) return 2*N;
	}

	if (N-1-x == y) {
		for (i=0; i<N; i++) if (s[c[card][N-1-i][i]] == false) break;
		if (i == N) return 2*N+1;
	}
	return -1;
}

int main() {

int C, i, j, k, S, tmp, cur, BESTS, D, tmpi, d[4];
bool num[100], flag;
vector<int> v;
vector<pt> pos[100];
pt tmppt;

srand(time(0));

cin >> C;
cin >> N;

do {

for (i=0; i<100; i++) pos[i].clear();
memset(num, false, sizeof(num)); v.clear();
for (k=0; k<C; k++) {
   for (i=0; i<N; i++) {
		for (j=0; j<N; j++) {
			cin >> c[k][i][j];
			tmppt.c = k; tmppt.x = i; tmppt.y = j;
			pos[c[k][i][j]].push_back(tmppt);
			if (num[c[k][i][j]] == false) {
				num[c[k][i][j]] = true;
				v.push_back(c[k][i][j]);
			}
		}
	}
}

BESTS = 101;
for (j=0; j<10000; j++) {

	S = D = 0; flag = true;
	memset(s, false, sizeof(s));
	memset(d, -1, sizeof(d));

	while (1) {
   	tmp = rand()%(v.size()-S);
	   cur = v[tmp]; s[cur] = true;
   	tmpi = v[v.size()-S-1];
		v[v.size()-S-1] = v[tmp];
		v[tmp] = tmpi;
		S++;

//		cout << "salio el " << cur; for (i=0; i<C; i++) cout << ' ' << d[i]; cout << endl;

		for (i=0; i<pos[cur].size(); i++) {
			if (d[pos[cur][i].c] == -1) {
				d[pos[cur][i].c] = check(pos[cur][i].c, pos[cur][i].x, pos[cur][i].y);
				if (d[pos[cur][i].c] != -1) {
					D++;
					if (D == 4) break;
					else if (pos[cur][i].c > 0 && d[pos[cur][i].c-1] == -1) {flag = false; break;}
				}
			}
		}
		if (i<pos[cur].size()) {
			if (flag == true) {
				memset(s, false, sizeof(s)); S = 0;
//				cout << "SALIERON ";
//				for (i=0; i<C; i++) cout << d[i] << ' ';
//				cout << " CON LOS NUMEROS ";
				for (i=0; i<C; i++) {
					for (k=0; k<N; k++) {
						if (d[i] < N) tmp = c[i][d[i]][k];
						else if (d[i] < 2*N) tmp = c[i][k][d[i]-N];
						else if (d[i] == 2*N) tmp = c[i][k][k];
						else tmp = c[i][N-1-k][k];
						if (s[tmp] == false) {
//							cout << tmp << ' ';
							s[tmp] = true;
							S++;
						}
					}
				}
//				cout << endl;
				if (BESTS > S) BESTS = S;
			}
			break;
		}
	}
//	cout << "sacamos " << S << " numeros y el resultado fue " << flag << endl << endl;

}
if (BESTS < 101) cout << BESTS << endl;
else cout << 0 << endl;

cin >> C;
cin >> N;

} while (N!=0 || C!=0);

return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 3380
final_rank: 2

code_snippet: #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <bitset>
#include <assert.h>

using namespace std;
typedef long long ll;
typedef set<int>::iterator ssii;

#define Cmp(a, b) memcmp(a, b, sizeof(b))
#define Cpy(a, b) memcpy(a, b, sizeof(b))
#define Set(a, v) memset(a, v, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define _forS(i, l, r) for(set<int>::iterator i = (l); i != (r); i++)
#define _rep(i, l, r) for(int i = (l); i <= (r); i++)
#define _for(i, l, r) for(int i = (l); i < (r); i++)
#define _forDown(i, l, r) for(int i = (l); i >= r; i--)
#define debug_(ch, i) printf(#ch"[%d]: %d\n", i, ch[i])
#define debug_m(mp, p) printf(#mp"[%d]: %d\n", p->first, p->second)
#define debugS(str) cout << "dbg: " << str << endl;
#define debugArr(arr, x, y) _for(i, 0, x) { _for(j, 0, y) printf("%c", arr[i][j]); printf("\n"); }
#define _forPlus(i, l, d, r) for(int i = (l); i + d < (r); i++)
#define lowbit(i) (i & (-i))
#define MPR(a, b) make_pair(a, b)

pair<int, int> crack(int n) {
    int st = sqrt(n);
    int fac = n / st;
    while (n % st) {
        st += 1;
        fac = n / st;
    }

    return make_pair(st, fac);
}

inline ll qpow(ll a, int n) {
    ll ans = 1;
    for(; n; n >>= 1) {
        if(n & 1) ans *= 1ll * a;
        a *= a;
    }
    return ans;
}

template <class T>
inline bool chmax(T& a, T b) {
    if(a < b) {
        a = b;
        return true;
    }
    return false;
}

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll ksc(ll a, ll b, ll mod) {
    ll ans = 0;
    for(; b; b >>= 1) {
        if (b & 1) ans = (ans + a) % mod;
        a = (a * 2) % mod;
    }
    return ans;
}

ll ksm(ll a, ll b, ll mod) {
    ll ans = 1 % mod;
    a %= mod;

    for(; b; b >>= 1) {
        if (b & 1) ans = ksc(ans, a, mod);
        a = ksc(a, a, mod);
    }

    return ans;
}

template <class T>
inline bool chmin(T& a, T b) {
    if(a > b) {
        a = b;
        return true;
    }
    return false;
}

bool _check(int x) {
    //
    return true;
}

int bsearch1(int l, int r) {
    while (l < r) {
        int mid = (l + r) >> 1;
        if(_check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

int bsearch2(int l, int r) {
    while (l < r) {
        int mid = (l + r + 1) >> 1;
        if(_check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

template<class T>
bool lexSmaller(vector<T> a, vector<T> b) {
    int n = a.size(), m = b.size();
    int i;
    for(i = 0; i < n && i < m; i++) {
        if (a[i] < b[i]) return true;
        else if (b[i] < a[i]) return false;
    }
    return (i == n && i < m);
}

// ============================================================== //

const int inf = 100;
const int maxn = 5;
const int maxl = 15;
int mat[maxn][maxn][maxn];
int a[maxn][maxl][maxn];
int n, m, K;

void prework(int p) {
    K = 0;
    _for(x, 0, m) {
        _for(y, 0, m) a[p][K][y] = mat[p][x][y];
        K++;
    }
    _for(y, 0, m) {
        _for(x, 0, m) a[p][K][x] = mat[p][x][y];
        K++;
    }

    _for(x, 0, m) {
        a[p][K][x] = mat[p][x][x];
    }
    K++;

    _for(x, 0, m) {
        a[p][K][x] = mat[p][x][m-1-x];
    }
    K++;

    assert(K == 2*m + 2);
}

int tim[inf + 5];
bool isChose[inf + 5];
bool mark[inf << 1];

bool isBingo(int p) {
    // check card p is bingo

    // check horizontal
    _for(x, 0, m) {
        bool ok = true;
        _for(y, 0, m) if (!mark[ mat[p][x][y] ]) { ok = false; break; }
        if (ok) return true;
    }
    // check vertical
    _for(y, 0, m) {
        bool ok = true;
        _for(x, 0, m) if (!mark[ mat[p][x][y] ]) { ok = false; break; }
        if (ok) return true;
    }

    // check slash 1
    bool ok = true;
    _for(x, 0, m) if (!mark[ mat[p][x][x] ]) { ok = false; break; }
    if (ok) return true;

    // check slash 2
    ok = true;
    _for(x, 0, m) if (!mark[ mat[p][x][m-1-x] ]) { ok = false; break; }
    if (ok) return true;

    return false;
}

bool isComplete() {
    _for(i, 0, n-1) if (!isBingo(i)) return false;
    return true;
}

bool valid() {
    bool ok = true;
    for (int i = 0; i < n; i++) {
        if (isBingo(i)) {
            if (!ok) return false;
        }
        else ok = false;
    }
    return true;
}

bool vis[1<<16];
int res = inf;
inline int cal() {
    // calculate the last card
    int ans = m+1;
    _for(i, 0, K) {
        int cnt = 0;
        _for(j, 0, m) if (!mark[ a[n-1][i][j] ]) cnt++;
        chmin(ans, cnt);
    }
    return ans;
}
void dfs2(const vector<int>& arr, int cnt, int sta) {
    if (vis[sta]) return;
    vis[sta] = true;

    if (!valid()) return;
    if (isComplete()) {
        res = min(res, cnt + cal());
        //debug(res);
        return;
    }

    // then enumerate permutation of arr
    for (int i = 0; i < arr.size(); i++) {
        int x = arr[i];
        if (mark[x]) continue;

        mark[x] = true;
        dfs2(arr, cnt + 1, sta | (1<<i));
        mark[x] = false;
    }
}

void dfs(int x) {
    if (x == n-1) {
        vector<int> arr;
        for (int i = 0; i < inf; i++) {
            if (isChose[i]) { arr.push_back(i); mark[i] = false; }
        }
        _for(i, 0, 1<<(arr.size())) vis[i] = 0;
        dfs2(arr, 0, 0);
        return;
    }

    for (int i = 0; i < K; i++) {
        // enumerate bingo posture i for card x
        _for(j, 0, m) {
            int val = a[x][i][j];
            if (tim[val] == -1) {
                tim[val] = x;
                isChose[val] = true;
            }
        }

        dfs(x+1);

        _for(j, 0, m) {
            int val = a[x][i][j];
            if (tim[val] == x) {
                tim[val] = -1;
                isChose[val] = false;
            }
        }
    }
}

void init() {
    memset(a, 0, sizeof(a));
    memset(tim, -1, sizeof(tim));
    memset(isChose, 0, sizeof(isChose));
    memset(mark, 0, sizeof(mark));
    memset(vis, 0, sizeof(vis));
    K = 0;
    res = inf;
}

int main() {
    //freopen("input.txt", "r", stdin);
    while (scanf("%d%d", &n, &m) == 2 && n) {
        init();

        // get data
        _for(i, 0, n) {
            _for(x, 0, m) _for(y, 0, m) scanf("%d", &mat[i][x][y]);
        }

        // prework and normalize
        _for(i, 0, n) prework(i);

        // then solve
        dfs(0);
        if (res == inf) printf("0\n");
        else printf("%d\n", res);
    }
}
accuracy: 1
time_ms: 2310
memory_kb: 3348
final_rank: 10

code_snippet: #include<iostream>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define ALL(C)     (C).begin(),(C).end()
#define pb         push_back

bool ischoosed[100];
int  check[100];
int bingo[4][4][4];

bool isbingo(int n,int p,bool *used){
  rep(i,n){
    bool isbingo=true;
    rep(j,n){
      if (!used[bingo[p][i][j]])isbingo=false;
    }
    if (isbingo)return true;
  }
  rep(i,n){
    bool isbingo=true;
    rep(j,n){
      if (!used[bingo[p][j][i]])isbingo=false;
    }
    if (isbingo)return true;
  }
  bool isbingo=true;
  rep(i,n){
    if (!used[bingo[p][i][i]])isbingo=false;
  }
  if (isbingo)return true;
  
  isbingo=true;
  rep(i,n){
    if (!used[bingo[p][i][n-1-i]])isbingo = false;
  }
  if (isbingo)return true;
  return false;
}

bool check_valid(int n,int player,bool *used){
  bool isok=true;
  rep(i,player){
    if (isbingo(n,i,used)){
      if (!isok)return false;
    }else isok=false;
  }
  return true;
}

int ans;

bool is_complete(int n,int player,bool *used){
  rep(i,player-1){
    if (!isbingo(n,i,used))return false;
  }
  return true;
}

int num[4][10][4];
void make_table(int n,int p){
  int total=0;
  rep(i,n){
    rep(j,n)num[p][total][j]=bingo[p][i][j];
    total++;
  }
  rep(i,n){
    rep(j,n)num[p][total][j]=bingo[p][j][i];
    total++;
  }
  rep(i,n){
    num[p][total][i]=bingo[p][i][i];
  }
  total++;
  rep(i,n){
    num[p][total][i]=bingo[p][i][n-1-i];
  }
  total++;
}

int require_last(int n ,int p,bool *used){
  int mini=n;
  int lim=n==3?8:10;
  rep(i,lim){
    int tmp=0;
    rep(j,n){
      if (!used[num[p][i][j]])tmp++;
    }
    mini=min(tmp,mini);
  }
  return mini;
}

bool search(int n,int player,int size,int *array,int cnt,bool *used,
	    bool *visited,int state){
  if (visited[state])return false;
  visited[state]=true;
  if (!check_valid(n,player,used)){
    return false;
  }

  if (is_complete(n,player,used)){
    //    cout << ans <<" " << cnt << endl;
    //rep(i,size)cout << used[i];
    //    cout << endl;
    //cout << ans <<" " << cnt <<" "<< require_last(n,player-1,used)<<endl;
    ans=min(ans,cnt+require_last(n,player-1,used));
    return true;
  }

  rep(i,size){
    if (used[array[i]])continue;
    used[array[i]]=true;
    if (search(n,player,size,array,cnt+1,used,visited,state|(1<<i))){
      used[array[i]]=false;
      return true;
    }
    used[array[i]]=false;
  }
  return false;
}

int array[100];
bool used[200];
bool visited[(1<<16)];
void search2(int n,int player,int now){
  if (now+1 == player){
    int p=0;
    rep(i,100){
      if (ischoosed[i]){
	array[p++]=i;
	used[i]=false;
      }
    }

    //    cout << p << endl;
    rep(i,(1<<p))visited[i]=false;
    
    /*
    rep(i,p){
      used[array[i]]=true;
    }
    if (p + require_last(n,player-1,used)> ans)return;
    rep(i,p){
      used[array[i]]=false;
    }
    */

    /*    
      cout <<"size "<< p << endl;
      rep(i,p){
	cout << array[i] <<" ";
      }
      cout << endl;
    */
    
    search(n,player,p,array,0,used,visited,0);
    return;
  }

  int lim = n==3?8:10;
  rep(i,lim){
    rep(j,n){
      if (check[num[now][i][j]] == -1){
	ischoosed[num[now][i][j]]=true;
	check[num[now][i][j]]=now;
      }
    }
    
    search2(n,player,now+1);
    
    rep(j,n){
      if (check[num[now][i][j]] == now){
	check[num[now][i][j]]=-1;
	ischoosed[num[now][i][j]]=false;
      }
    }
  }
  return;
}



main(){
  int player,n;
  while(cin>>player>>n && player){
    rep(k,player){
      rep(i,n){
	rep(j,n){
	  cin>>bingo[k][i][j];
	}
      }
    }

    rep(i,100){
      ischoosed[i]=false;
      check[i]=-1;
    }

    rep(k,player){
      make_table(n,k);
    }

    ans = 100;
    search2(n,player,0);
    if (ans == 100)cout << 0 << endl;
    else cout << ans << endl;
  }
  return false;
}
accuracy: 1
time_ms: 1240
memory_kb: 3108
final_rank: 5

code_snippet: #include<iostream>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define ALL(C)     (C).begin(),(C).end()
#define pb         push_back

bool ischoosed[100];
int  check[100];
int bingo[4][4][4];

bool isbingo(int n,int p,bool *used){
  rep(i,n){
    bool isbingo=true;
    rep(j,n){
      if (!used[bingo[p][i][j]])isbingo=false;
    }
    if (isbingo)return true;
  }
  rep(i,n){
    bool isbingo=true;
    rep(j,n){
      if (!used[bingo[p][j][i]])isbingo=false;
    }
    if (isbingo)return true;
  }
  bool isbingo=true;
  rep(i,n){
    if (!used[bingo[p][i][i]])isbingo=false;
  }
  if (isbingo)return true;
  
  isbingo=true;
  rep(i,n){
    if (!used[bingo[p][i][n-1-i]])isbingo = false;
  }
  if (isbingo)return true;
  return false;
}

bool check_valid(int n,int player,bool *used){
  bool isok=true;
  rep(i,player){
    if (isbingo(n,i,used)){
      if (!isok)return false;
    }else isok=false;
  }
  return true;
}

int ans;

bool is_complete(int n,int player,bool *used){
  rep(i,player-1){
    if (!isbingo(n,i,used))return false;
  }
  return true;
}

int num[4][10][4];
void make_table(int n,int p){
  int total=0;
  rep(i,n){
    rep(j,n)num[p][total][j]=bingo[p][i][j];
    total++;
  }
  rep(i,n){
    rep(j,n)num[p][total][j]=bingo[p][j][i];
    total++;
  }
  rep(i,n){
    num[p][total][i]=bingo[p][i][i];
  }
  total++;
  rep(i,n){
    num[p][total][i]=bingo[p][i][n-1-i];
  }
  total++;
}

int require_last(int n ,int p,bool *used){
  int mini=n;
  int lim=n==3?8:10;
  rep(i,lim){
    int tmp=0;
    rep(j,n){
      if (!used[num[p][i][j]])tmp++;
    }
    mini=min(tmp,mini);
  }
  return mini;
}

bool search(int n,int player,int size,int *array,int cnt,bool *used,
	    bool *visited,int state){
  if (visited[state])return false;
  visited[state]=true;
  if (!check_valid(n,player,used)){
    return false;
  }

  if (is_complete(n,player,used)){
    //    cout << ans <<" " << cnt << endl;
    //rep(i,size)cout << used[i];
    //    cout << endl;
    //cout << ans <<" " << cnt <<" "<< require_last(n,player-1,used)<<endl;
    ans=min(ans,cnt+require_last(n,player-1,used));
    return true;
  }

  rep(i,size){
    if (used[array[i]])continue;
    used[array[i]]=true;
    if (search(n,player,size,array,cnt+1,used,visited,state|(1<<i))){
      used[array[i]]=false;
      return true;
    }
    used[array[i]]=false;
  }
  return false;
}

int array[100];
bool used[200];
bool visited[(1<<16)];
void search2(int n,int player,int now){
  if (now+1 == player){
    int p=0;
    rep(i,100){
      if (ischoosed[i]){
	array[p++]=i;
	used[i]=false;
      }
    }

    //    cout << p << endl;
    rep(i,(1<<p))visited[i]=false;
    
    /*
    rep(i,p){
      used[array[i]]=true;
    }
    if (p + require_last(n,player-1,used)> ans)return;
    rep(i,p){
      used[array[i]]=false;
    }
    */

    /*    
      cout <<"size "<< p << endl;
      rep(i,p){
	cout << array[i] <<" ";
      }
      cout << endl;
    */
    
    search(n,player,p,array,0,used,visited,0);
    return;
  }

  int lim = n==3?8:10;
  rep(i,lim){
    rep(j,n){
      if (check[num[now][i][j]] == -1){
	ischoosed[num[now][i][j]]=true;
	check[num[now][i][j]]=now;
      }
    }
    
    search2(n,player,now+1);
    
    rep(j,n){
      if (check[num[now][i][j]] == now){
	check[num[now][i][j]]=-1;
	ischoosed[num[now][i][j]]=false;
      }
    }
  }
  return;
}



main(){
  int player,n;
  while(cin>>player>>n && player){
    rep(k,player){
      rep(i,n){
	rep(j,n){
	  cin>>bingo[k][i][j];
	}
      }
    }

    rep(i,100){
      ischoosed[i]=false;
      check[i]=-1;
    }

    rep(k,player){
      make_table(n,k);
    }

    ans = 100;
    search2(n,player,0);
    if (ans == 100)cout << 0 << endl;
    else cout << ans << endl;
  }
  return false;
}
accuracy: 1
time_ms: 1240
memory_kb: 3008
final_rank: 3

code_snippet: #include <set>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>

#define REP(i,n) for(int i=0; i<(int)(n); i++)

inline int getInt(){ int s; scanf("%d", &s); return s; }

using namespace std;

int n, m;

int bingo[4][4][4];
int hit[4][4];
int nums[4 * 4];
int ans;

vector<pair<int, pair<int, int> > > memo[100];

bool bingoCheck(int hit[4]){
  // tate
  REP(i,m){
    if(hit[i] == (1 << m) - 1) return true;
  }
  // yoko
  int tmp = (1 << m) - 1;
  REP(i,m){
    tmp &= hit[i];
  }
  if(tmp != 0) return true;

  {
    // naname1
    int cnt = 0;
    REP(i,m) cnt += (hit[i] & (1 << i)) != 0;
    if(cnt == m) return true;
  }
  {
    // naname2
    int cnt = 0;
    REP(i,m) cnt += (hit[i] & (1 << (m - i - 1))) != 0;
    if(cnt == m) return true;
  }
  return false;
}

void bingoGo(int num, bool which){
  REP(c, memo[num].size()){
    int i = memo[num][c].first;
    int j = memo[num][c].second.first;
    int k = memo[num][c].second.second;

    if(which)
      hit[i][j] |= (1 << k);
    else
      hit[i][j] &= ~(1 << k);
  }
}

bool dp[1<<12];
int nn[4 * 4];
int ns;

bool cango(int flag){
  if(flag == (1 << ns) - 1) return true;
  if(dp[flag]) return false;
  dp[flag] = true;

  REP(i,ns) if((flag & (1 << i)) == 0){
    bingoGo(nn[i], true);

    int ff = 0;
    REP(j,n) if(bingoCheck(hit[j])) ff |= (1 << j);

    bool ok = true;
    REP(j,n-1) if((ff & (1 << j)) == 0 && (ff & (1 << (j + 1))) != 0){
      ok = false;
      break;
    }

    if(ok && cango(flag ^ (1 << i)))
      return true;

    bingoGo(nn[i], false);
  }
  return false;
}

bool check(){
  REP(i,(n - 1) * m) nn[i] = nums[i];
  sort(nn, nn + (n - 1) * m);
  ns = unique(nn, nn + (n - 1) * m) - nn;
  memset(dp, 0, 1 << ns);
  return cango(0);
}

int restMin(){
  set<int> s(nums, nums + (n - 1) * m);
  vector<int> v(s.begin(), s.end());

  REP(i,n) REP(j,m) hit[i][j] = 0;
  REP(i,v.size()){
    bingoGo(v[i], true);
  }

  int ret = 1000;
  int *hh = hit[n - 1];

  // tate
  REP(i,m){
    int cnt = 0;
    REP(j,m) if(hh[j] & (1 << i))
      cnt++;
    ret = min(ret, m - cnt);
  }
  // yoko
  REP(i,m){
    int cnt = 0;
    REP(j,m) if(hh[i] & (1 << j))
      cnt++;
    ret = min(ret, m - cnt);
  }
  //naname1
  {
    int cnt = 0;
    REP(i,m) if(hh[i] & (1 << i))
      cnt++;
    ret = min(ret, m - cnt);
  }
  //naname2
  {
    int cnt = 0;
    REP(i,m) if(hh[i] & (1 << (m - i - 1)))
      cnt++;
    ret = min(ret, m - cnt);
  }
  return ret;
}

void solve(int pos){
  if(pos == n - 1){
    int tmp = set<int>(nums, nums + (n - 1) * m).size()
      + restMin();

    if(tmp < ans){
      REP(i,n) REP(j,m) hit[i][j] = 0;
      if(check()) ans = tmp;
    }
    return;
  }

  // tate
  REP(i,m){
    REP(j,m){
      nums[pos * m + j] = bingo[pos][j][i];
    }
    solve(pos + 1);
  }

  // yoko
  REP(i,m){
    REP(j,m){
      nums[pos * m + j] = bingo[pos][i][j];
    }
    solve(pos + 1);
  }

  // naname1
  REP(i,m){
    nums[pos * m + i] = bingo[pos][i][i];
  }
  solve(pos + 1);

  // naname2
  REP(i,m){
    nums[pos * m + i] = bingo[pos][m - i - 1][i];
  }
  solve(pos + 1);
}

int main(){
  while(true){
    n = getInt();
    m = getInt();

    if(n + m == 0) break;

    REP(i,100) memo[i] = vector<pair<int, pair<int, int> > >();

    REP(i,n){
      REP(j,m) REP(k,m){
	bingo[i][j][k] = getInt();
	memo[bingo[i][j][k]].push_back(make_pair(i, make_pair(j, k)));
      }
    }

    ans = 1000;
    solve(0);
    if(ans == 1000) ans = 0;
    printf("%d\n", ans);
  }
  return 0;
}
accuracy: 1
time_ms: 1760
memory_kb: 3168
final_rank: 9

code_snippet: #include <iostream>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

struct pt {
   int c, x, y;
};

int c[4][4][4], N;
bool s[100];

int check(int card, int x, int y) {
	int i;

   for (i=0; i<N; i++) if (s[c[card][x][i]] == false) break;
	if (i == N) return x;

   for (i=0; i<N; i++) if (s[c[card][i][y]] == false) break;
	if (i == N) return N + y;

	if (x == y) {
	   for (i=0; i<N; i++) if (s[c[card][i][i]] == false) break;
		if (i == N) return 2*N;
	}

	if (N-1-x == y) {
		for (i=0; i<N; i++) if (s[c[card][N-1-i][i]] == false) break;
		if (i == N) return 2*N+1;
	}
	return -1;
}

int main() {

int C, i, j, k, S, tmp, cur, BESTS, D, tmpi, d[4];
bool num[100], flag;
vector<int> v;
vector<pt> pos[100];
pt tmppt;

srand(time(0));

cin >> C;
cin >> N;

do {

for (i=0; i<100; i++) pos[i].clear();
memset(num, false, sizeof(num)); v.clear();
for (k=0; k<C; k++) {
   for (i=0; i<N; i++) {
		for (j=0; j<N; j++) {
			cin >> c[k][i][j];
			tmppt.c = k; tmppt.x = i; tmppt.y = j;
			pos[c[k][i][j]].push_back(tmppt);
			if (num[c[k][i][j]] == false) {
				num[c[k][i][j]] = true;
				v.push_back(c[k][i][j]);
			}
		}
	}
}

BESTS = 101;
for (j=0; j<10000; j++) {

	S = D = 0; flag = true;
	memset(s, false, sizeof(s));
	memset(d, -1, sizeof(d));

	while (1) {
   	tmp = rand()%(v.size()-S);
	   cur = v[tmp]; s[cur] = true;
   	tmpi = v[v.size()-S-1];
		v[v.size()-S-1] = v[tmp];
		v[tmp] = tmpi;
		S++;

//		cout << "salio el " << cur; for (i=0; i<C; i++) cout << ' ' << d[i]; cout << endl;

		for (i=0; i<pos[cur].size(); i++) {
			if (d[pos[cur][i].c] == -1) {
				d[pos[cur][i].c] = check(pos[cur][i].c, pos[cur][i].x, pos[cur][i].y);
				if (d[pos[cur][i].c] != -1) {
					D++;
					if (D == 4) break;
					else if (pos[cur][i].c > 0 && d[pos[cur][i].c-1] == -1) {flag = false; break;}
				}
			}
		}
		if (i<pos[cur].size()) {
			if (flag == true) {
				memset(s, false, sizeof(s)); S = 0;
//				cout << "SALIERON ";
//				for (i=0; i<C; i++) cout << d[i] << ' ';
//				cout << " CON LOS NUMEROS ";
				for (i=0; i<C; i++) {
					for (k=0; k<N; k++) {
						if (d[i] < N) tmp = c[i][d[i]][k];
						else if (d[i] < 2*N) tmp = c[i][k][d[i]-N];
						else if (d[i] == 2*N) tmp = c[i][k][k];
						else tmp = c[i][N-1-k][k];
						if (s[tmp] == false) {
//							cout << tmp << ' ';
							s[tmp] = true;
							S++;
						}
					}
				}
//				cout << endl;
				if (BESTS > S) BESTS = S;
			}
			break;
		}
	}
//	cout << "sacamos " << S << " numeros y el resultado fue " << flag << endl << endl;

}
if (BESTS < 101) cout << BESTS << endl;
else cout << 0 << endl;

cin >> C;
cin >> N;

} while (N!=0 || C!=0);

return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 1224
final_rank: 1

code_snippet: #include <set>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>

#define REP(i,n) for(int i=0; i<(int)(n); i++)

inline int getInt(){ int s; scanf("%d", &s); return s; }

using namespace std;

int n, m;

int bingo[4][4][4];
int hit[4][4];
int nums[4 * 4];
int ans;

vector<pair<int, pair<int, int> > > memo[100];

bool bingoCheck(int hit[4]){
  // tate
  REP(i,m){
    if(hit[i] == (1 << m) - 1) return true;
  }
  // yoko
  int tmp = (1 << m) - 1;
  REP(i,m){
    tmp &= hit[i];
  }
  if(tmp != 0) return true;

  {
    // naname1
    int cnt = 0;
    REP(i,m) cnt += (hit[i] & (1 << i)) != 0;
    if(cnt == m) return true;
  }
  {
    // naname2
    int cnt = 0;
    REP(i,m) cnt += (hit[i] & (1 << (m - i - 1))) != 0;
    if(cnt == m) return true;
  }
  return false;
}

void bingoGo(int num, bool which){
  REP(c, memo[num].size()){
    int i = memo[num][c].first;
    int j = memo[num][c].second.first;
    int k = memo[num][c].second.second;

    if(which)
      hit[i][j] |= (1 << k);
    else
      hit[i][j] &= ~(1 << k);
  }
}

bool dp[1<<12];
int nn[4 * 4];
int ns;

bool cango(int flag){
  if(flag == (1 << ns) - 1) return true;
  if(dp[flag]) return false;
  dp[flag] = true;

  REP(i,ns) if((flag & (1 << i)) == 0){
    bingoGo(nn[i], true);

    int ff = 0;
    REP(j,n) if(bingoCheck(hit[j])) ff |= (1 << j);

    bool ok = true;
    REP(j,n-1) if((ff & (1 << j)) == 0 && (ff & (1 << (j + 1))) != 0){
      ok = false;
      break;
    }

    if(ok && cango(flag ^ (1 << i)))
      return true;

    bingoGo(nn[i], false);
  }
  return false;
}

bool check(){
  REP(i,(n - 1) * m) nn[i] = nums[i];
  sort(nn, nn + (n - 1) * m);
  ns = unique(nn, nn + (n - 1) * m) - nn;
  memset(dp, 0, 1 << ns);
  return cango(0);
}

int restMin(){
  set<int> s(nums, nums + (n - 1) * m);
  vector<int> v(s.begin(), s.end());

  REP(i,n) REP(j,m) hit[i][j] = 0;
  REP(i,v.size()){
    bingoGo(v[i], true);
  }

  int ret = 1000;
  int *hh = hit[n - 1];

  // tate
  REP(i,m){
    int cnt = 0;
    REP(j,m) if(hh[j] & (1 << i))
      cnt++;
    ret = min(ret, m - cnt);
  }
  // yoko
  REP(i,m){
    int cnt = 0;
    REP(j,m) if(hh[i] & (1 << j))
      cnt++;
    ret = min(ret, m - cnt);
  }
  //naname1
  {
    int cnt = 0;
    REP(i,m) if(hh[i] & (1 << i))
      cnt++;
    ret = min(ret, m - cnt);
  }
  //naname2
  {
    int cnt = 0;
    REP(i,m) if(hh[i] & (1 << (m - i - 1)))
      cnt++;
    ret = min(ret, m - cnt);
  }
  return ret;
}

void solve(int pos){
  if(pos == n - 1){
    int tmp = set<int>(nums, nums + (n - 1) * m).size()
      + restMin();

    if(tmp < ans){
      REP(i,n) REP(j,m) hit[i][j] = 0;
      if(check()) ans = tmp;
    }
    return;
  }

  // tate
  REP(i,m){
    REP(j,m){
      nums[pos * m + j] = bingo[pos][j][i];
    }
    solve(pos + 1);
  }

  // yoko
  REP(i,m){
    REP(j,m){
      nums[pos * m + j] = bingo[pos][i][j];
    }
    solve(pos + 1);
  }

  // naname1
  REP(i,m){
    nums[pos * m + i] = bingo[pos][i][i];
  }
  solve(pos + 1);

  // naname2
  REP(i,m){
    nums[pos * m + i] = bingo[pos][m - i - 1][i];
  }
  solve(pos + 1);
}

int main(){
  while(true){
    n = getInt();
    m = getInt();

    if(n + m == 0) break;

    REP(i,100) memo[i] = vector<pair<int, pair<int, int> > >();

    REP(i,n){
      REP(j,m) REP(k,m){
	bingo[i][j][k] = getInt();
	memo[bingo[i][j][k]].push_back(make_pair(i, make_pair(j, k)));
      }
    }

    ans = 1000;
    solve(0);
    if(ans == 1000) ans = 0;
    printf("%d\n", ans);
  }
  return 0;
}
accuracy: 1
time_ms: 4060
memory_kb: 940
final_rank: 7

code_snippet: #include <set>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>

#define REP(i,n) for(int i=0; i<(int)(n); i++)

inline int getInt(){ int s; scanf("%d", &s); return s; }

using namespace std;

int n, m;

int bingo[4][4][4];
int hit[4][4];
int nums[4 * 4];
int ans;

vector<pair<int, pair<int, int> > > memo[100];

bool bingoCheck(int hit[4]){
  // tate
  REP(i,m){
    if(hit[i] == (1 << m) - 1) return true;
  }
  // yoko
  int tmp = (1 << m) - 1;
  REP(i,m){
    tmp &= hit[i];
  }
  if(tmp != 0) return true;

  {
    // naname1
    int cnt = 0;
    REP(i,m) cnt += (hit[i] & (1 << i)) != 0;
    if(cnt == m) return true;
  }
  {
    // naname2
    int cnt = 0;
    REP(i,m) cnt += (hit[i] & (1 << (m - i - 1))) != 0;
    if(cnt == m) return true;
  }
  return false;
}

void bingoGo(int num, bool which){
  REP(c, memo[num].size()){
    int i = memo[num][c].first;
    int j = memo[num][c].second.first;
    int k = memo[num][c].second.second;

    if(which)
      hit[i][j] |= (1 << k);
    else
      hit[i][j] &= ~(1 << k);
  }
}

bool dp[1<<16];
int nn[4 * 4];
int ns;

bool cango(int flag){
  if(flag == (1 << ns) - 1) return true;
  if(dp[flag]) return false;
  dp[flag] = true;

  REP(i,ns) if((flag & (1 << i)) == 0){
    bingoGo(nn[i], true);

    int ff = 0;
    REP(j,n) if(bingoCheck(hit[j])) ff |= (1 << j);

    bool ok = true;
    REP(j,n-1) if((ff & (1 << j)) == 0 && (ff & (1 << (j + 1))) != 0){
      ok = false;
      break;
    }

    if(ok && cango(flag ^ (1 << i)))
      return true;

    bingoGo(nn[i], false);
  }
  return false;
}

bool check(){
  memset(dp, 0, sizeof(dp));
  REP(i,(n - 1) * m) nn[i] = nums[i];
  sort(nn, nn + (n - 1) * m);
  ns = unique(nn, nn + (n - 1) * m) - nn;
  return cango(0);
}

int restMin(){
  set<int> s(nums, nums + (n - 1) * m);
  vector<int> v(s.begin(), s.end());

  REP(i,n) REP(j,m) hit[i][j] = 0;
  REP(i,v.size()){
    bingoGo(v[i], true);
  }

  int ret = 1000;
  int *hh = hit[n - 1];

  // tate
  REP(i,m){
    int cnt = 0;
    REP(j,m) if(hh[j] & (1 << i))
      cnt++;
    ret = min(ret, m - cnt);
  }
  // yoko
  REP(i,m){
    int cnt = 0;
    REP(j,m) if(hh[i] & (1 << j))
      cnt++;
    ret = min(ret, m - cnt);
  }
  //naname1
  {
    int cnt = 0;
    REP(i,m) if(hh[i] & (1 << i))
      cnt++;
    ret = min(ret, m - cnt);
  }
  //naname2
  {
    int cnt = 0;
    REP(i,m) if(hh[i] & (1 << (m - i - 1)))
      cnt++;
    ret = min(ret, m - cnt);
  }
  return ret;
}

void solve(int pos){
  if(pos == n - 1){
    int tmp = set<int>(nums, nums + (n - 1) * m).size()
      + restMin();

    if(tmp < ans){
      REP(i,n) REP(j,m) hit[i][j] = 0;
      if(check()) ans = tmp;
    }
    return;
  }

  // tate
  REP(i,m){
    REP(j,m){
      nums[pos * m + j] = bingo[pos][j][i];
    }
    solve(pos + 1);
  }

  // yoko
  REP(i,m){
    REP(j,m){
      nums[pos * m + j] = bingo[pos][i][j];
    }
    solve(pos + 1);
  }

  // naname1
  REP(i,m){
    nums[pos * m + i] = bingo[pos][i][i];
  }
  solve(pos + 1);

  // naname2
  REP(i,m){
    nums[pos * m + i] = bingo[pos][m - i - 1][i];
  }
  solve(pos + 1);
}

int main(){
  while(true){
    n = getInt();
    m = getInt();

    if(n + m == 0) break;

    REP(i,100) memo[i] = vector<pair<int, pair<int, int> > >();

    REP(i,n){
      REP(j,m) REP(k,m){
	bingo[i][j][k] = getInt();
	memo[bingo[i][j][k]].push_back(make_pair(i, make_pair(j, k)));
      }
    }

    ans = 1000;
    solve(0);
    if(ans == 1000) ans = 0;
    printf("%d\n", ans);
  }
  return 0;
}
accuracy: 1
time_ms: 4070
memory_kb: 996
final_rank: 8

code_snippet: #include<iostream>
#include<map>
#include<algorithm>
#include<vector>
using namespace std;
#define REP(i,b,n) for(int i=b;i<n;i++)
#define rep(i,n)   REP(i,0,n)
#define ALL(C)     (C).begin(),(C).end()
#define pb         push_back

bool ischoosed[100];
int  check[100];
int bingo[4][4][4];

bool isbingo(int n,int p,bool *used){
  rep(i,n){
    bool isbingo=true;
    rep(j,n){
      if (!used[bingo[p][i][j]])isbingo=false;
    }
    if (isbingo)return true;
  }
  rep(i,n){
    bool isbingo=true;
    rep(j,n){
      if (!used[bingo[p][j][i]])isbingo=false;
    }
    if (isbingo)return true;
  }
  bool isbingo=true;
  rep(i,n){
    if (!used[bingo[p][i][i]])isbingo=false;
  }
  if (isbingo)return true;
  
  isbingo=true;
  rep(i,n){
    if (!used[bingo[p][i][n-1-i]])isbingo = false;
  }
  if (isbingo)return true;
  return false;
}

bool check_valid(int n,int player,bool *used){
  bool isok=true;
  rep(i,player){
    if (isbingo(n,i,used)){
      if (!isok)return false;
    }else isok=false;
  }
  return true;
}

int ans;

bool is_complete(int n,int player,bool *used){
  rep(i,player-1){
    if (!isbingo(n,i,used))return false;
  }
  return true;
}

int num[4][10][4];
void make_table(int n,int p){
  int total=0;
  rep(i,n){
    rep(j,n)num[p][total][j]=bingo[p][i][j];
    total++;
  }
  rep(i,n){
    rep(j,n)num[p][total][j]=bingo[p][j][i];
    total++;
  }
  rep(i,n){
    num[p][total][i]=bingo[p][i][i];
  }
  total++;
  rep(i,n){
    num[p][total][i]=bingo[p][i][n-1-i];
  }
  total++;
}

int require_last(int n ,int p,bool *used){
  int mini=n;
  int lim=n==3?8:10;
  rep(i,lim){
    int tmp=0;
    rep(j,n){
      if (!used[num[p][i][j]])tmp++;
    }
    mini=min(tmp,mini);
  }
  return mini;
}

bool search(int n,int player,int size,int *array,int cnt,bool *used,
	    bool *visited,int state){
  if (visited[state])return false;
  visited[state]=true;
  if (!check_valid(n,player,used)){
    return false;
  }

  if (is_complete(n,player,used)){
    //    cout << ans <<" " << cnt << endl;
    //rep(i,size)cout << used[i];
    //    cout << endl;
    //cout << ans <<" " << cnt <<" "<< require_last(n,player-1,used)<<endl;
    ans=min(ans,cnt+require_last(n,player-1,used));
    return true;
  }

  rep(i,size){
    if (used[array[i]])continue;
    used[array[i]]=true;
    if (search(n,player,size,array,cnt+1,used,visited,state|(1<<i))){
      used[array[i]]=false;
      return true;
    }
    used[array[i]]=false;
  }
  return false;
}

int array[100];
bool used[200];
bool visited[(1<<16)];
void search2(int n,int player,int now){
  if (now+1 == player){
    int p=0;
    rep(i,100){
      if (ischoosed[i]){
	array[p++]=i;
	used[i]=false;
      }
    }

    //    cout << p << endl;
    rep(i,(1<<p))visited[i]=false;
    
    /*
    rep(i,p){
      used[array[i]]=true;
    }
    if (p + require_last(n,player-1,used)> ans)return;
    rep(i,p){
      used[array[i]]=false;
    }
    */

    /*    
      cout <<"size "<< p << endl;
      rep(i,p){
	cout << array[i] <<" ";
      }
      cout << endl;
    */
    
    search(n,player,p,array,0,used,visited,0);
    return;
  }

  int lim = n==3?8:10;
  rep(i,lim){
    rep(j,n){
      if (check[num[now][i][j]] == -1){
	ischoosed[num[now][i][j]]=true;
	check[num[now][i][j]]=now;
      }
    }
    
    search2(n,player,now+1);
    
    rep(j,n){
      if (check[num[now][i][j]] == now){
	check[num[now][i][j]]=-1;
	ischoosed[num[now][i][j]]=false;
      }
    }
  }
  return;
}



main(){
  int player,n;
  while(cin>>player>>n && player){
    rep(k,player){
      rep(i,n){
	rep(j,n){
	  cin>>bingo[k][i][j];
	}
      }
    }

    rep(i,100){
      ischoosed[i]=false;
      check[i]=-1;
    }

    rep(k,player){
      make_table(n,k);
    }

    ans = 100;
    search2(n,player,0);
    if (ans == 100)cout << 0 << endl;
    else cout << ans << endl;
  }
  return false;
}
accuracy: 1
time_ms: 3570
memory_kb: 872
final_rank: 4