#include <bits/stdc++.h>
using namespace std;
int n;
int weight[2000 + 5][2000 + 5];
bool added[2000 + 5];
priority_queue<pair<int, pair<int, int> >, vector<pair<int, pair<int, int> > >,
               greater<pair<int, pair<int, int> > > >
    pQ;
void enqueuTOPQ(int u) {
  added[u] = true;
  for (int i = 1; i <= n; i++) {
    if (!added[i]) {
      pQ.push({weight[u][i], {u, i}});
    }
  }
}
vector<pair<int, int> > graph[2000 + 5];
bool possible;
void dfs(int u, int p, int s, int w) {
  if (p != -1) {
    if (weight[s][u] == 0 || weight[s][u] != w) {
      possible = false;
      return;
    }
  } else {
    if (weight[s][s] != 0) {
      possible = false;
      return;
    }
  }
  for (auto v : graph[u]) {
    if (v.first != p) {
      dfs(v.first, u, s, w + v.second);
      if (!possible) {
        return;
      }
    }
  }
}
int main() {
  int i, j, d;
  scanf("%d", &n);
  for (i = 1; i <= n; i++) {
    for (j = 1; j <= n; j++) {
      scanf("%d", &weight[i][j]);
    }
  }
  enqueuTOPQ(1);
  while (!pQ.empty()) {
    auto p = pQ.top();
    pQ.pop();
    if (!added[p.second.second]) {
      graph[p.second.first].push_back({p.second.second, p.first});
      graph[p.second.second].push_back({p.second.first, p.first});
      enqueuTOPQ(p.second.second);
    }
  }
  possible = true;
  for (i = 1; i <= n; i++) {
    dfs(i, -1, i, 0);
  }
  if (possible) {
    cout << "YES";
  } else {
    cout << "NO";
  }
  return 0;
}
