#include <bits/stdc++.h>
using namespace std;
const int N = 2000;
const long long duzo = 1000000001;
long long n, d[N + 10][N + 10], dist[N + 10];
bool in[N + 10], vis[N + 10];
struct Edges {
  long long to;
  long long w;
};
struct VERT {
  long long from;
  long long w;
};
VERT vert[N + 10];
vector<Edges> edges[N + 10], vec[N + 10];
vector<long long> rem;
void fail() {
  cout << "NO";
  exit(0);
}
void DFS(int x, long long cost) {
  dist[x] = cost;
  vis[x] = 1;
  for (int i = 0; i < edges[x].size(); ++i) {
    if (!vis[edges[x][i].to]) {
      DFS(edges[x][i].to, cost + edges[x][i].w);
    }
  }
}
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> n;
  for (int i = 0; i < n; ++i) {
    for (int j = 0; j < n; ++j) {
      cin >> d[i][j];
      if (i != j) vec[i].push_back({j, d[i][j]});
    }
  }
  for (int i = 0; i < n; ++i)
    for (int j = 0; j < n; ++j)
      if (i != j && d[i][j] == 0) fail();
  in[0] = 1;
  for (int i = 0; i < vec[0].size(); ++i) {
    vert[vec[0][i].to].w = vec[0][i].w;
    vert[vec[0][i].to].from = 0;
    rem.push_back(vec[0][i].to);
  }
  while (!rem.empty()) {
    long long w = duzo;
    int it, from, to;
    for (int i = 0; i < rem.size(); ++i) {
      if (vert[rem[i]].w < w) {
        to = rem[i];
        it = i;
        from = vert[rem[i]].from;
        w = vert[rem[i]].w;
      }
    }
    edges[vert[to].from].push_back({to, vert[to].w});
    edges[to].push_back({vert[to].from, vert[to].w});
    for (int i = 0; i < vec[to].size(); ++i) {
      if (vert[vec[to][i].to].w > vec[to][i].w) {
        vert[vec[to][i].to].w = vec[to][i].w;
        vert[vec[to][i].to].from = to;
      }
    }
    swap(rem[it], rem.back());
    rem.pop_back();
  }
  for (int i = 0; i < n; ++i) {
    DFS(i, 0);
    for (int j = 0; j < n; ++j) {
      if (dist[j] != d[i][j]) {
        fail();
      }
      vis[j] = 0;
    }
  }
  cout << "YES";
}
