#include <algorithm>
#include <bitset>
#include <cctype>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <numeric>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>

using namespace std;

#define FOR(i, first, last) for (int i = (first); i < (last); ++i)
#define REP(i, n) FOR(i, 0, n)
#define CLR(a) memset((a), 0, sizeof(a))
#define DUMP(x) std::cerr << #x << " = " << (x) << std::endl;
#define DUMPR(v) REP(_i,v.size()){std::cerr<< #v << "[" << _i << "] = " << (v[_i]) << std::endl;}
#define CIN_VEC(v,N) {v.clear(); v.reserve(N); REP(i,N){typename decltype(v)::value_type x; cin>>x; v.emplace_back(x);}};

inline int to_int(string s) {
  int v;
  istringstream sin(s);
  sin >> v;
  return v;
}
template <class T> inline string to_string(T x) {
  ostringstream sout;
  sout << x;
  return sout.str();
}

typedef unsigned long long ull;
typedef unsigned long ul;

void test(int N) {
  REP(i, N) {
    REP(j, N) {
      int ii = i+1;
      int jj = j+1;
      printf("%2d", (ii+jj)%3);
    }
    printf("\n");
  }

}

int main() {
  int N,C;
  cin>>N>>C;

  vector<vector<int>> D(C), colors(N);
  REP(i,C) D[i].resize(C);
  REP(i,N) 
    colors[i].resize(N);

  REP(i, C) {
    REP(j, C) {
      int x; cin >> x;
      D[j][i] = x; // transpose
    }
  }
  REP(i, N) {
    REP(j, N) {
      int x; cin >> x;
      colors[i][j] = x;
    }
  }

  vector<int> c[3];

  REP(i, N) {
    REP(j, N) {
      int mod = ((i+1) + (j+1)) % 3;
      int cl = colors[i][j];
      c[mod].push_back(cl);
      // DUMP(cl);
    }
  }


  int ans = 1000000000;

  vector<int> memo[3];
  REP(mod,3) {
    memo[mod].resize(C);
    fill(memo[mod].begin(), memo[mod].end(), 0);

    REP(col, C) {
      memo[mod][col] = 0;
      for(int p : c[mod])
        memo[mod][col] += D[col][p-1];
    }
  }


  for(int x=1; x<=C; x++) {
    for(int y=1; y<=C;y++) {
      if(x==y)continue;
      for(int z=1; z<=C; z++) {
        if(x==z||y==z) continue;
        // DUMP(x);
        // DUMP(y);
        // DUMP(z);

        int iwakan = memo[0][x-1] + memo[1][y-1] + memo[2][z-1];
        ans = min(iwakan, ans);

        // int iwakan = 0;
        // if(memo[0][x-1] == -1) {
        //   int s = 0;
        //   const auto& DD = D[x-1];
        //   for (int p : c[0])
        //     s += DD[p-1];
        //   memo[0][x-1] = s;
        // }
        // if(memo[1][y-1] == -1) {
        //   int s = 0;
        //   const auto& DD = D[y-1];
        //   for (int p : c[1])
        //     s += DD[p-1];
        //   memo[1][x-1] = s;
        // }
        // if(memo[2][z-1] == -1) {
        //   int s = 0;
        //   const auto& DD = D[z-1];
        //   for (int p : c[2])
        //     s += DD[p-1];
        //   memo[2][z-1] = s;
        // }
        // ans = min(
        //     ans,
        //     memo[0][x-1] + memo[1][y-1] + memo[2][z-1]
        //     );
        //
        //
        // // const auto& D0 = D[x-1];
        // // const auto& D1 = D[y-1];
        // // const auto& D2 = D[z-1];
        // //
        // // int iwakan = 0;
        // // for (int p : c[0])
        // //   iwakan += D0[p-1];
        // // for (int p : c[1])
        // //   iwakan += D1[p-1];
        // // for (int p : c[2])
        // //   iwakan += D2[p-1];
        // // ans = min(ans, iwakan);
        // // DUMP(ans);
      }
    }
  }
  cout<<ans<<endl;

  return 0;
}


Measured memory_bytes: 2428