#include <bits/stdc++.h>
using namespace std;
struct node {
  int u, v, w;
  node() {}
  node(int a, int b, int c) : u(a), v(b), w(c) {}
  bool operator<(node p) const { return w < p.w; }
};
vector<pair<int, int> > ady_list[2005];
static int pset[4000005], dist[2005][2005], d[2005][2005];
void initSet(int n) {
  for (int i = 0; i < n; i++) pset[i] = i;
}
int findSet(int u) {
  return ((u == pset[u]) ? u : (pset[u] = findSet(pset[u])));
}
void unionSet(int a, int b) { pset[findSet(a)] = findSet(b); }
bool isSameSet(int a, int b) { return (findSet(a) == findSet(b)); }
bool vis[2005];
void dfs(int t, int s, int sum) {
  if (vis[t]) return;
  d[s][t] = d[t][s] = sum;
  vis[t] = 1;
  for (int i = 0; i < ady_list[t].size(); i++) {
    pair<int, int> aux = ady_list[t][i];
    dfs(aux.first, s, sum + aux.second);
  }
}
int main() {
  static int n;
  bool sol = true;
  vector<node> graph;
  scanf("%d", &n);
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++) {
      scanf("%d", &dist[i][j]);
      graph.push_back(node(i, j, dist[i][j]));
      if (i == j && dist[i][j] > 0) sol = false;
    }
  sort((graph).begin(), (graph).end());
  initSet(n * n + 1);
  for (int i = 0; i < n * n; i++) {
    if (!isSameSet(graph[i].u, graph[i].v)) {
      unionSet(graph[i].u, graph[i].v);
      ady_list[graph[i].u].push_back(pair<int, int>(graph[i].v, graph[i].w));
      ady_list[graph[i].v].push_back(pair<int, int>(graph[i].u, graph[i].w));
    }
  }
  for (int i = 0; i < n; i++) {
    memset(vis, false, sizeof vis);
    dfs(i, i, 0);
  }
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
      if (i != j && (dist[i][j] == 0 || d[i][j] == 0)) sol = false;
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
      if (dist[i][j] != d[i][j]) sol = false;
  printf("%s\n", ((sol) ? "YES" : "NO"));
  return 0;
}
