#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;
}

Measured memory_bytes: 872