output_description: If the minimum possible sum of the wrongness of all the squares is x, print x.
  
  * * *
input_description: Input is given from Standard Input in the following format:
  
      
      
      N C
      D_{1,1} ... D_{1,C}
      :
      D_{C,1} ... D_{C,C}
      c_{1,1} ... c_{1,N}
      :
      c_{N,1} ... c_{N,N}
attempt: ###############################################################################
  
  from sys import stdout
  from bisect import bisect_left as binl
  from copy import copy, deepcopy
  from collections import defaultdict
  
  
  mod = 1
  
  
  def intin():
      input_tuple = input().split()
      if len(input_tuple) <= 1:
          return int(input_tuple[0])
      return tuple(map(int, input_tuple))
  
  
  def intina():
      return [int(i) for i in input().split()]
  
  
  def intinl(count):
      return [intin() for _ in range(count)]
  
  
  def modadd(x, y):
      global mod
      return (x + y) % mod
  
  
  def modmlt(x, y):
      global mod
      return (x * y) % mod
  
  
  def lcm(x, y):
      while y != 0:
          z = x % y
          x = y
          y = z
      return x
  
  
  def combination(x, y):
      assert x >= y
  
      if y > x // 2:
          y = x - y
  
      ret = 1
  
      for i in range(0, y):
          j = x - i
          i = i + 1
  
          ret = ret * j
          ret = ret // i
  
      return ret
  
  
  def get_divisors(x):
      retlist = []
      for i in range(1, int(x**0.5) + 3):
          if x % i == 0:
              retlist.append(i)
              retlist.append(x // i)
      return retlist
  
  
  def get_factors(x):
      retlist = []
      for i in range(2, int(x**0.5) + 3):
          while x % i == 0:
              retlist.append(i)
              x = x // i
      retlist.append(x)
      return retlist
  
  
  def make_linklist(xylist):
      linklist = {}
      for a, b in xylist:
          linklist.setdefault(a, [])
          linklist.setdefault(b, [])
          linklist[a].append(b)
          linklist[b].append(a)
      return linklist
  
  
  def calc_longest_distance(linklist, v=1):
      distance_list = {}
      distance_count = 0
      distance = 0
      vlist_previous = []
      vlist = [v]
      nodecount = len(linklist)
  
      while distance_count < nodecount:
          vlist_next = []
          for v in vlist:
              distance_list[v] = distance
              distance_count += 1
              vlist_next.extend(linklist[v])
          distance += 1
          vlist_to_del = vlist_previous
          vlist_previous = vlist
          vlist = list(set(vlist_next) - set(vlist_to_del))
  
      max_distance = -1
      max_v = None
      for v, distance in distance_list.items():
          if distance > max_distance:
              max_distance = distance
              max_v = v
  
      return (max_distance, max_v)
  
  
  def calc_tree_diameter(linklist, v=1):
      _, u = calc_longest_distance(linklist, v)
      distance, _ = calc_longest_distance(linklist, u)
      return distance
  
  
  ###############################################################################
  
  
  def main():
      n, c = intin()
      dlistlist = [None]
      for _ in range(c):
          dlist = [None]
          dlist.extend(intina())
          dlistlist.append(dlist)
      clistlist = []
      for _ in range(n):
          clistlist.append(intina())
  
      costs0 = []
      costs1 = []
      costs2 = []
  
      for cc in range(1, c + 1):
  
          costs = [0, 0, 0]
  
          for i in range(n):
              for j in range(n):
                  costs[(i + j) % 3] += dlistlist[clistlist[i][j]][cc]
  
          costs0.append((costs[0], cc))
          costs1.append((costs[1], cc))
          costs2.append((costs[2], cc))
  
      costs0.sort()
      costs1.sort()
      costs2.sort()
  
      ans = float("inf")
      for cost0, c0 in costs0[:3]:
          for cost1, c1 in costs1[:3]:
              for cost2, c2 in costs2[:3]:
                  if c0 == c1 or c1 == c2 or c2 == c0:
                      continue
                  ans = min(ans, cost0 + cost1 + cost2)
  
      print(ans)
  
  
  if __name__ == "__main__":
      main()
  
problem_description: Statement
  
  There is a grid with N rows and N columns of squares. Let (i,j) be the square
  at the i-th row from the top and the j-th column from the left.
  
  These squares have to be painted in one of the C colors from Color 1 to Color
  C. Initially, (i,j) is painted in Color c_{i,j}.
  
  We say the grid is a _good_ grid when the following condition is met for all
  i,j,x,y satisfying 1 \leq i,j,x,y \leq N:
  
    * If (i+j) \% 3=(x+y) \% 3, the color of (i,j) and the color of (x,y) are the same.
    * If (i+j) \% 3 \neq (x+y) \% 3, the color of (i,j) and the color of (x,y) are different.
  
  Here, X \% Y represents X modulo Y.
  
  We will repaint zero or more squares so that the grid will be a good grid.
  
  For a square, the _wrongness_ when the color of the square is X before
  repainting and Y after repainting, is D_{X,Y}.
  
  Find the minimum possible sum of the wrongness of all the squares.
samples: [{"input": "2 3\n    0 1 1\n    1 0 1\n    1 4 0\n    1 2\n    3 3", "output": "3\n    \n\n  * Repaint (1,1) to Color 2. The wrongness of (1,1) becomes D_{1,2}=1.\n  * Repaint (1,2) to Color 3. The wrongness of (1,2) becomes D_{2,3}=1.\n  * Repaint (2,2) to Color 1. The wrongness of (2,2) becomes D_{3,1}=1.\n\nIn this case, the sum of the wrongness of all the squares is 3.\n\nNote that D_{i,j} \\neq D_{j,i} is possible.\n\n* * *"}, {"input": "4 3\n    0 12 71\n    81 0 53\n    14 92 0\n    1 1 2 1\n    2 1 1 2\n    2 2 1 3\n    1 1 2 2", "output": "428"}]