#include <bits/stdc++.h>
using namespace std;
std::mt19937 rnd(
    (int)std::chrono::steady_clock::now().time_since_epoch().count());
long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); }
struct MaxFlow {
  int n;
  vector<int> ghead, gnxt, gto;
  vector<long long> gcap;
  vector<int> d;
  queue<int> q;
  vector<int> cur;
  void init(int _n) {
    n = _n;
    ghead = vector<int>(n, -1);
    gnxt = gto = vector<int>();
    gcap = vector<long long>();
  }
  int addedgewithflow(int a, int b, long long cap, long long flow) {
    gnxt.push_back(ghead[a]);
    ghead[a] = ((int)(gnxt).size()) - 1;
    gto.push_back(b);
    gcap.push_back(cap - flow);
    gnxt.push_back(ghead[b]);
    ghead[b] = ((int)(gnxt).size()) - 1;
    gto.push_back(a);
    gcap.push_back(flow);
    return ((int)(gnxt).size()) - 2;
  }
  int addedge(int a, int b, long long cap) {
    return addedgewithflow(a, b, cap, 0);
  }
  long long dfs(int at, int t, long long rem) {
    long long ret = 0;
    if (at == t) return rem;
    if (d[at] >= d[t]) return 0;
    for (; cur[at] != -1; cur[at] = gnxt[cur[at]]) {
      int to = gto[cur[at]];
      long long cap = gcap[cur[at]];
      if (d[to] != d[at] + 1 || cap == 0) continue;
      long long now = dfs(to, t, min(cap, rem));
      rem -= now;
      ret += now;
      if (gcap[cur[at]] != LLONG_MAX) gcap[cur[at]] -= now;
      if (gcap[cur[at] ^ 1] != LLONG_MAX) gcap[cur[at] ^ 1] += now;
      if (rem == 0) return ret;
    }
    return ret;
  }
  long long solve(int s, int t) {
    long long ret = 0;
    while (true) {
      d = vector<int>(n, INT_MAX);
      q = queue<int>();
      d[s] = 0, q.push(s);
      while (!q.empty() && d[t] == INT_MAX) {
        int at = q.front();
        q.pop();
        for (int x = ghead[at]; x != -1; x = gnxt[x]) {
          int to = gto[x];
          if (gcap[x] == 0 || d[to] != INT_MAX) continue;
          d[to] = d[at] + 1, q.push(to);
        }
      }
      if (d[t] == INT_MAX) return ret;
      cur = ghead;
      ret += dfs(s, t, LLONG_MAX);
    }
  }
  long long getflow(int x) { return gcap[x ^ 1]; }
  vector<int> findpath(int s, int t) {
    vector<int> back(n, -2);
    queue<int> q;
    back[s] = -1, q.push(s);
    while (!q.empty()) {
      int at = q.front();
      q.pop();
      for (int x = ghead[at]; x != -1; x = gnxt[x]) {
        if (gcap[x ^ 1] == 0 || back[gto[x]] != -2) continue;
        back[gto[x]] = x ^ 1, q.push(gto[x]);
      }
    }
    assert(back[t] != -2);
    vector<int> ret;
    for (int x = back[t]; x != -1; x = back[gto[x]]) ret.push_back(x ^ 1);
    reverse(ret.begin(), ret.end());
    for (int x : ret) {
      ++gcap[x], --gcap[x ^ 1];
    }
    return ret;
  }
  long long removeedge(int s, int t, int x) {
    long long ret = gcap[x ^ 1];
    gcap[x] = gcap[x ^ 1] = 0;
    assert(ret <= 1);
    for (int i = (0); i < (ret); ++i) {
      findpath(s, gto[x ^ 1]);
      findpath(gto[x], t);
    }
    return ret;
  }
};
const int MAXN = 200;
const int DX[] = {-1, 0, +1, 0}, DY[] = {0, +1, 0, -1};
int n;
vector<vector<int>> a;
vector<int> v;
MaxFlow mf;
long long solve() {
  v.clear();
  for (int i = (0); i < (n); ++i)
    for (int j = (0); j < (n); ++j)
      if (a[i][j] == 0) a[i][j] = -2;
  for (int i = (0); i < (n); ++i)
    for (int j = (0); j < (n); ++j)
      if (a[i][j] >= 0) v.push_back(a[i][j]);
  sort(v.begin(), v.end());
  v.erase(unique(v.begin(), v.end()), v.end());
  for (int i = (0); i < (n); ++i)
    for (int j = (0); j < (n); ++j)
      if (a[i][j] >= 0)
        a[i][j] = lower_bound(v.begin(), v.end(), a[i][j]) - v.begin();
  int nid = 0;
  int sid = nid++, tid = nid++;
  vector<vector<int>> id(n, vector<int>(n, -1));
  for (int x = (0); x < (n); ++x)
    for (int y = (0); y < (n); ++y)
      if (a[x][y] != -1) id[x][y] = nid++;
  vector<vector<int>> who(((int)(v).size()));
  for (int x = (0); x < (n); ++x)
    for (int y = (0); y < (n); ++y)
      if (a[x][y] >= 0) who[a[x][y]].push_back(id[x][y]);
  long long ret = 0;
  mf.init(nid);
  for (int x = (0); x < (n); ++x)
    for (int y = (0); y < (n); ++y)
      for (int k = (0); k < (2); ++k)
        if (a[x][y] != -1) {
          int nx = x + DX[k], ny = y + DY[k];
          if (nx < 0 || ny >= n || ny < 0 || ny >= n || a[nx][ny] == -1)
            continue;
          if ((x == 0 || x == n - 1 || y == 0 || y == n - 1) &&
              (nx == 0 || nx == n - 1 || ny == 0 || ny == n - 1)) {
            ret += abs(v[a[x][y]] - v[a[nx][ny]]);
          } else {
            mf.addedgewithflow(id[x][y], id[nx][ny], 2, 1);
          }
        }
  vector<int> edge(nid, -1);
  for (int x = (0); x < (n); ++x)
    for (int y = (0); y < (n); ++y)
      if (a[x][y] >= 0) edge[id[x][y]] = mf.addedge(id[x][y], tid, 1);
  int flow = 0;
  for (int i = (0); i < (((int)(v).size()) - 1); ++i) {
    for (int j = (0); j < (((int)(who[i]).size())); ++j) {
      int at = who[i][j];
      assert(edge[at] != -1);
      flow -= mf.removeedge(sid, tid, edge[at]);
      mf.addedge(sid, at, 1);
      edge[at] = -1;
    }
    flow += mf.solve(sid, tid);
    ret += (long long)flow * (v[i + 1] - v[i]);
  }
  return ret;
}
void run() {
  scanf("%d", &n);
  a = vector<vector<int>>(n, vector<int>(n));
  for (int i = (0); i < (n); ++i)
    for (int j = (0); j < (n); ++j) scanf("%d", &a[i][j]);
  printf("%lld\n", solve());
}
void stresstime() {
  int mxn = 10;
  for (int rep = (0); rep < (10); ++rep) {
    n = MAXN;
    a = vector<vector<int>>(n, vector<int>(n, 0));
    int freq = rnd() % 40 + 1;
    for (int i = (0); i < (n); ++i)
      for (int j = (0); j < (n); ++j) {
        if (i == 0 || i == n - 1 || j == 0 || j == n - 1)
          a[i][j] = rnd() % 1000 + 1;
        else if (rnd() % freq == 0)
          a[i][j] = -1;
      }
    solve();
    printf(".");
  }
}
int main() {
  run();
  return 0;
}
