#include <bits/stdc++.h>
using namespace std;
const long long inf = (1 << 30);
const int mod = (int)1e9 + 7;
long long read() {
  bool minus = false;
  long long result = 0;
  char ch;
  ch = getchar();
  while (true) {
    if (ch == '-') break;
    if (ch >= '0' && ch <= '9') break;
    ch = getchar();
  }
  if (ch == '-')
    minus = true;
  else
    result = ch - '0';
  while (true) {
    ch = getchar();
    if (ch < '0' || ch > '9') break;
    result = result * 10 + (ch - '0');
  }
  if (minus) {
    return -result;
  } else {
    return result;
  }
}
long long fpow(long long base, long long power) {
  long long result = 1;
  while (power > 0) {
    if (power % 2 == 1) result = (result * base);
    base = (base * base);
    power /= 2;
  }
  return result;
}
vector<pair<long long, pair<long long, long long> > > edges;
vector<pair<long long, long long> > tree[2100];
long long Parent[2100], rankk[2100], dp[2100][2100];
void make_set() {
  for (long long i = 1; i <= 2002; i++) {
    Parent[i] = i;
    rankk[i] = 0;
  }
}
long long find(long long x) {
  if (x != Parent[x]) {
    Parent[x] = find(Parent[x]);
  }
  return Parent[x];
}
void uunion(long long x, long long y) {
  long long PX = find(x), PY = find(y);
  if (PX == PY) {
    return;
  }
  if (rankk[PX] > rankk[PY]) {
    Parent[PY] = PX;
  } else {
    Parent[PX] = PY;
    if (rankk[PX] == rankk[PY]) {
      rankk[PY]++;
    }
  }
}
bool fla = false;
void dfs(long long par, long long node, long long root, long long we) {
  if (dp[root][node] != we) {
    fla = true;
  }
  for (long long i = 0; i < tree[node].size(); i++) {
    long long v = tree[node][i].first;
    if (v != par) {
      dfs(node, v, root, min(we + tree[node][i].second, inf));
    }
  }
}
bool check(long long n) {
  for (long long i = 1; i <= n; i++) {
    if (dp[i][i] != 0) {
      return 0;
    }
  }
  for (long long i = 1; i <= n; i++) {
    for (long long j = 1; j <= n; j++)
      if (i != j) {
        if (dp[i][j] == 0) return 0;
        if (dp[i][j] != dp[j][i]) return 0;
      }
  }
  return 1;
}
int main() {
  long long n, i, j;
  n = read();
  for (i = 1; i <= n; i++)
    for (j = 1; j <= n; j++) dp[i][j] = read();
  if (!check(n)) return 0 * printf("NO\n");
  make_set();
  for (i = 1; i <= n; i++)
    for (j = 1; j <= i; j++)
      edges.push_back(make_pair(dp[i][j], make_pair(i, j)));
  sort(edges.begin(), edges.end());
  for (i = 0; i < edges.size(); i++) {
    long long u = edges[i].second.first;
    long long v = edges[i].second.second;
    long long w = edges[i].first;
    if (find(u) != find(v)) {
      uunion(u, v);
      tree[u].push_back(make_pair(v, w));
      tree[v].push_back(make_pair(u, w));
    }
  }
  fla = false;
  for (i = 1; i <= n; i++) {
    dfs(-1, i, i, 0);
  }
  if (fla) {
    return 0 * printf("NO\n");
  }
  printf("YES\n");
}
