#include <bits/stdc++.h>
template <class C, class E>
inline bool contains(const C &container, const E &element) {
  return container.find(element) != container.end();
}
template <class T>
inline void checkmin(T &a, T b) {
  if (b < a) a = b;
}
template <class T>
inline void checkmax(T &a, T b) {
  if (b > a) a = b;
}
using namespace std;
struct Node {
  Node() {}
  Node(int goinTo, pair<int, int> pos, int type)
      : _goingTo(goinTo), _pos(pos), _type(type) {}
  int _goingTo;
  pair<int, int> _pos;
  int _type;
};
vector<pair<int, int>> distances;
vector<Node> father;
int total;
int posCount;
int n;
map<int, pair<int, int>> pos;
pair<int, int> Add(pair<int, int> a, pair<int, int> b) {
  return pair<int, int>(a.first + b.first, a.second + b.second);
}
bool IsValid(int p) { return p >= 0 && p < n; }
bool IsValid(pair<int, int> p) { return IsValid(p.first) && IsValid(p.second); }
bool CanMoveCaballo(pair<int, int> a, pair<int, int> b) {
  if (!IsValid(a) || !IsValid(b)) return false;
  int deltaX = abs(a.first - b.first);
  int deltaY = abs(a.second - b.second);
  return (deltaX == 2 && deltaY == 1) || (deltaX == 1 && deltaY == 2);
}
bool CanMoveTorre(pair<int, int> a, pair<int, int> b) {
  if (!IsValid(a) || !IsValid(b)) return false;
  int deltaX = abs(a.first - b.first);
  int deltaY = abs(a.second - b.second);
  return (deltaX == 0 || deltaY == 0);
}
bool CanMoveAlfil(pair<int, int> a, pair<int, int> b) {
  if (!IsValid(a) || !IsValid(b)) return false;
  int deltaX = abs(a.first - b.first);
  int deltaY = abs(a.second - b.second);
  return (deltaX == deltaY);
}
int PosToNodeId(pair<int, int> p) { return p.first * n + p.second; }
vector<bool> visit;
int NodeToPos(const Node &node) {
  if (node._goingTo == 0) return 0;
  if (node._goingTo == 1) return total - 1;
  return 1 + (node._goingTo - 2) * posCount * 3 + node._type * posCount +
         node._pos.first + node._pos.second * n;
}
bool operator<(const Node &n1, const Node &n2) {
  return NodeToPos(n1) < NodeToPos(n2);
}
vector<vector<vector<pair<int, int>>>> nextPos[3];
vector<pair<int, int>> GetNextPoss(pair<int, int> p, int type) {
  return nextPos[type][p.first][p.second];
}
vector<pair<Node, pair<int, int>>> Vecinos(const Node &n) {
  vector<pair<Node, pair<int, int>>> res;
  if (n._goingTo == 0) {
    res.push_back(make_pair(Node(2, pos[1], 0), pair<int, int>(0, 0)));
    res.push_back(make_pair(Node(2, pos[1], 1), pair<int, int>(0, 0)));
    res.push_back(make_pair(Node(2, pos[1], 2), pair<int, int>(0, 0)));
  } else if (n._goingTo == 1) {
  } else {
    pair<int, int> destino = pos[n._goingTo];
    if (n._type != 0)
      res.push_back(
          make_pair(Node(n._goingTo, n._pos, 0), pair<int, int>(1, 1)));
    if (n._type != 1)
      res.push_back(
          make_pair(Node(n._goingTo, n._pos, 1), pair<int, int>(1, 1)));
    if (n._type != 2)
      res.push_back(
          make_pair(Node(n._goingTo, n._pos, 2), pair<int, int>(1, 1)));
    if (n._pos == destino) {
      int a = 0;
    }
    int newGoingTo = (n._pos != destino) ? n._goingTo : n._goingTo + 1;
    if (newGoingTo != posCount + 1) {
      vector<pair<int, int>> nextPoss = GetNextPoss(n._pos, n._type);
      for (pair<int, int> p : nextPoss)
        res.push_back(
            make_pair(Node(newGoingTo, p, n._type), pair<int, int>(1, 0)));
    } else
      res.push_back(
          make_pair(Node(1, pair<int, int>(0, 0), 0), pair<int, int>(0, 0)));
  }
  return res;
}
void dijkstra() {
  int iter = 0;
  priority_queue<pair<pair<int, int>, Node>> queue;
  pair<pair<int, int>, Node> nodotmp;
  for (int i = (0), _b = ((total)-1); i <= _b; i++) {
    distances[i] = pair<int, int>(100000000, 100000000);
    visit[i] = false;
  }
  Node ss;
  ss._goingTo = 0;
  distances[NodeToPos(ss)] = pair<int, int>(0, 0);
  queue.push(pair<pair<int, int>, Node>(distances[NodeToPos(ss)], ss));
  while (!queue.empty()) {
    Node thisNode;
    ++iter;
    nodotmp = queue.top();
    queue.pop();
    thisNode = nodotmp.second;
    int thisNodePos = NodeToPos(thisNode);
    if (!visit[thisNodePos]) {
      visit[thisNodePos] = true;
      vector<pair<Node, pair<int, int>>> vecinos = Vecinos(thisNode);
      for (auto jd : vecinos) {
        Node &j = jd.first;
        pair<int, int> &distThisNodej = jd.second;
        int jPos = NodeToPos(j);
        if (!visit[jPos] &&
            distThisNodej != pair<int, int>(100000000, 100000000) &&
            Add(distances[thisNodePos], distThisNodej) < distances[jPos]) {
          distances[jPos] = Add(distances[thisNodePos], distThisNodej);
          father[jPos] = thisNode;
          queue.push(pair<pair<int, int>, Node>(
              pair<int, int>(-distances[jPos].first, -distances[jPos].second),
              j));
        }
      }
    }
  }
}
string Name(int type) {
  if (type == 0)
    return "Alf";
  else if (type == 1)
    return "Cab";
  else
    return "Torre";
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  cout << std::setprecision(15);
  cout << std::fixed;
  cin >> n;
  for (int y = (0), _b = ((n)-1); y <= _b; y++) {
    for (int x = (0), _b = ((n)-1); x <= _b; x++) {
      int p;
      cin >> p;
      pos[p] = make_pair(x, y);
    }
  }
  posCount = n * n;
  total = posCount * (posCount - 1) * 3 + 2;
  distances.resize(total, pair<int, int>(100000000, 100000000));
  father.resize(total);
  visit.resize(total, false);
  for (int i = (0), _b = ((3) - 1); i <= _b; i++)
    nextPos[i] = vector<vector<vector<pair<int, int>>>>(
        n, vector<vector<pair<int, int>>>(n));
  for (int y1 = (0), _b = ((n)-1); y1 <= _b; y1++) {
    for (int x1 = (0), _b = ((n)-1); x1 <= _b; x1++) {
      for (int y2 = (0), _b = ((n)-1); y2 <= _b; y2++) {
        for (int x2 = (0), _b = ((n)-1); x2 <= _b; x2++) {
          pair<int, int> from(x1, y1);
          pair<int, int> to(x2, y2);
          if (from != to) {
            if (CanMoveCaballo(from, to)) nextPos[1][x1][y1].push_back(to);
            if (CanMoveAlfil(from, to)) nextPos[0][x1][y1].push_back(to);
            if (CanMoveTorre(from, to)) nextPos[2][x1][y1].push_back(to);
          }
        }
      }
    }
  }
  dijkstra();
  cout << distances[total - 1].first << " " << distances[total - 1].second;
  return 0;
}
