#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#include <string>
#include <numeric>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <iterator>
#include <fstream>
#include <cstddef>
#include <cstring>

using namespace std;

typedef pair<int, int> P;
typedef long long ll;
#define PB push_back
#define rep(i, a) for(int i = 0; i < a; i++)
#define all(v) v.begin(),v.end()
#define FF first
#define SS second
#define mp make_pair
#define INT int_64
#define MOD 998244353
const ll INF = (1<<30);
const ll NEGA=-INF*10000; 

//階乗
ll Kaijou(ll a) {
if (a < 2) return 1;
return a * Kaijou(a - 1)%MOD;
}

//逆元の計算用(pは素数のときb=p-2で逆元)
ll calc(ll a, ll b, ll p) {
	if (b == 0) return 1;
	if (b % 2 == 0) {
		ll d = calc(a, b / 2, p);
		return (d*d) % p;
	}
	else {
		return (a*calc(a, b - 1, p)) % p;
	}
}


//ユークリッドの互除法
ll gcd(ll x, ll y) {
	if (x < y) swap(x, y);
	if (y == 0) return x;
	return gcd(y, x%y);
}

ll CCC(ll all,ll a,ll b,ll c){
  all=Kaijou(all)%MOD;
  a=Kaijou(a);
  b=Kaijou(b);
  c=Kaijou(c);
  ll sita=((a*b)%MOD*c)%MOD;
  return all*calc(sita,MOD-2,MOD)%MOD;
}

 ll ans=INF;

 ll cc[501][501];
 ll D[31][31];
 
 ll pdmin[3];

int main(){
 
  ll n,c;
  cin>>n>>c;
  rep(i,c) rep(j,c) {
    cin>>D[i][j];
    }
  rep(i,n) rep(j,n) cin>>cc[i][j];
  
 rep(k,3){
   pdmin[k]=INF;
 }

 ll pd[3]={0};
 ll used[3]={-1,-1,-1};
rep(k,3){
  rep(m,c){
      pd[k]=0;
   rep(i,n) rep(j,n){
    if((i+j)%3==k) pd[k]+=D[cc[i][j]-1][m];
   }
   if(pdmin[k]>=pd[k]&&used[0]!=m&&used[1]!=m&&used[2]!=m){
     used[k]=m;
     pdmin[k]=pd[k];
   }
   }
 }
 ans=min(ans,pdmin[0]+pdmin[1]+pdmin[2]);
 rep(k,3){
   pdmin[k]=INF;
 }
used[2]=used[1]=used[0]=-1;
rep(k,3){
  rep(m,c){
      pd[(k+1)%3]=0;
   rep(i,n) rep(j,n){
    if((i+j)%3==k) pd[(k+1)%3]+=D[cc[i][j]-1][m];
   }
   if(pdmin[(k+1)%3]>=pd[(k+1)%3]&&used[0]!=m&&used[1]!=m&&used[2]!=m){
     used[(k+1)%3]=m;
     pdmin[(k+1)%3]=pd[(k+1)%3];
   }
   }
 }
 ans=min(ans,pdmin[0]+pdmin[1]+pdmin[2]);
 rep(k,3){
   pdmin[k]=INF;
 }
used[2]=used[1]=used[0]=-1;
rep(k,3){
  rep(m,c){
      pd[(k+2)%3]=0;
   rep(i,n) rep(j,n){
    if((i+j)%3==k) pd[(k+2)%3]+=D[cc[i][j]-1][m];
   }
   if(pdmin[(k+2)%3]>=pd[(k+2)%3]&&used[0]!=m&&used[1]!=m&&used[2]!=m){
     used[(k+2)%3]=m;
     pdmin[(k+2)%3]=pd[(k+2)%3];
   }
   }
 }
 ans=min(ans,pdmin[0]+pdmin[1]+pdmin[2]);
 rep(k,3){
   pdmin[k]=INF;
 }
int cnt=0;
used[2]=used[1]=used[0]=-1;
while(cnt<3){
  int k;
  if(cnt==0) k=0;
  if(cnt==1) k=2;
  if(cnt==2) k=1;
  rep(m,c){
      pd[k]=0;
   rep(i,n) rep(j,n){
    if((i+j)%3==k) pd[k]+=D[cc[i][j]-1][m];
   }
   if(pdmin[k]>=pd[k]&&used[0]!=m&&used[1]!=m&&used[2]!=m){
     used[k]=m;
     pdmin[k]=pd[k];
   }
   }
   cnt++;
 }
 ans=min(ans,pdmin[0]+pdmin[1]+pdmin[2]);

 rep(k,3){
   pdmin[k]=INF;
 }
cnt=0;
used[2]=used[1]=used[0]=-1;
while(cnt<3){
  int k;
  if(cnt==0) k=1;
  if(cnt==1) k=0;
  if(cnt==2) k=2;
  rep(m,c){
      pd[k]=0;
   rep(i,n) rep(j,n){
    if((i+j)%3==k) pd[k]+=D[cc[i][j]-1][m];
   }
   if(pdmin[k]>=pd[k]&&used[0]!=m&&used[1]!=m&&used[2]!=m){
     used[k]=m;
     pdmin[k]=pd[k];
   }
   }
   cnt++;
 }
 ans=min(ans,pdmin[0]+pdmin[1]+pdmin[2]);
 rep(k,3){
   pdmin[k]=INF;
 }
cnt=0;
used[2]=used[1]=used[0]=-1;
while(cnt<3){
  int k;
  if(cnt==0) k=2;
  if(cnt==1) k=1;
  if(cnt==2) k=0;
  rep(m,c){
      pd[k]=0;
   rep(i,n) rep(j,n){
    if((i+j)%3==k) pd[k]+=D[cc[i][j]-1][m];
   }
   if(pdmin[k]>=pd[k]&&used[0]!=m&&used[1]!=m&&used[2]!=m){
     used[k]=m;
     pdmin[k]=pd[k];
   }
   }
   cnt++;
 }
 ans=min(ans,pdmin[0]+pdmin[1]+pdmin[2]);

  cout<<ans<<endl;
}

Measured memory_bytes: 2176