#include <stdio.h>
#include <string.h>

int n, maxchar[27][27];
	int c[30], max = 0, nr;
	char w[1001];

int main()
{

	scanf("%d", &n);
	for (int i =0; i<n; i++){
		scanf("%s", w);

		//verificam daca cuvintul nu are mai multe de 2 litere dinsincte
		for (int k = 0; k<27; k++) c[k] = 0;
		for (unsigned j = 0; j<strlen(w); j++) {
			c[w[j]-'a']++;
		}
		nr = 0;
		for (int j = 0; j<27; j++) {
			if (c[j]>0) nr++;
		}

		if (nr==2) {
			int k1 = -1, k2 = -1;
			int j = 0;
			while (c[j]==0 && j<27) j++;
			k1 = j; j++;
			while (c[j]==0 && j<27) j++;
			k2 = j; j++;
			maxchar[ k1] [ k2] += strlen(w);
		}
		if (nr==1) {
			int k1 = -1;
			int j = 0;
			while (c[j]==0 && j<27) j++;
			k1 = j; j++;
			for (int l=0; l<26; l++) {
				maxchar[l][k1] += strlen(w);
				maxchar[k1][l] += strlen(w);
			}
			maxchar[k1][k1] -= strlen(w);
		}

	}

	for (int i = 0; i<26; i++)
		for (int j =0; j<26; j++)
			if (maxchar[i][j]>max) {
				max = maxchar[i][j];
			}

	printf("%d\n", max);
	return 0;
}


#include<stdio.h>
int check(char *q){
 int a,i;
 int len=strlen(q);
int cnt=0;
 for(a='a';a<='z';a++){
        for(i=0;i<len;i++){
                if(*(q+i)==a){
                        cnt++;
                break;
                }
        }
 }
 if(cnt>2)
    return 0;
 return 1;
}
int main(){
int a,b,c,d;
scanf("%d",&a);
getchar();
char arr[200][200];
int i;
for(i=0;i<a;i++){
        gets(arr[i]);
}
int max=0;
for(i=0;i<a;i++){
        char compute[5000];
        char old[5000];
        strcpy(compute,arr[i]);
        strcpy(old,compute);
        if(strlen(compute)>max && check(compute))
            max=strlen(compute);
        for(b=0;b<a;b++){
                if(b==i){
                        continue;}
                strcat(compute,arr[b]);
                if(check(compute)){
                        if(strlen(compute)>max)
                        {
                            max=strlen(compute);
                        }
                    strcpy(old,compute);
                }
                else{
                        strcpy(compute,old);
                }
        }
}
printf("%d",max);

}


#include<stdio.h>
char arr[2000][2000];
int compare(char *q,char *b){
    return *q-*b;
}
int check(char *q){
int a,i;
int cnt=0;
int len=strlen(q);
qsort(q,len,sizeof(char),compare);
for(i=0;i<len;i++){
int temp=q[i];
while(q[i]==temp){
        i++;
}
i--;
cnt++;
}
 if(cnt>2)
    return 0;
 return 1;
}
int main(){
int a,b,c,d;
scanf("%d",&a);
getchar();
int i;
for(i=0;i<a;i++){
        gets(arr[i]);
}
int max=0;
for(i=0;i<a;i++){
        char compute[20000];
        char old[20000];
        strcpy(compute,arr[i]);
        strcpy(old,compute);
        int len=strlen(compute);
        if(len>max && check(compute))
            max=len;
        for(b=0;b<a;b++){
                if(b==i){
                        continue;}
                strcat(compute,arr[b]);
                if(check(compute)){
                int len=strlen(compute);
                        if(len>max)
                        {
                            max=len;
                        }
                    strcpy(old,compute);
                }
                else{
                        strcpy(compute,old);
                }
        }
}
printf("%d",max);

}


#include<stdio.h>
char arr[2000][2000];
int check(char *q){
int a,i;
int cnt=0;
int len=strlen(q);
for(i=0;i<len;i++){
        for(a=0;a<len-1;a++){
            if(q[a]>q[a+1]){
                    int temp=q[a];
                    q[a]=q[a+1];
                    q[a+1]=temp;
            }
        }
}

for(i=0;i<len;i++){
int temp=q[i];
while(q[i]==temp){
        i++;
}
i--;
cnt++;
}
 if(cnt>2)
    return 0;
 return 1;
}
int main(){
int a,b,c,d;
scanf("%d",&a);
getchar();
int i;
for(i=0;i<a;i++){
        gets(arr[i]);
}
int max=0;
for(i=0;i<a;i++){
        char compute[20000];
        char old[20000];
        strcpy(compute,arr[i]);
        strcpy(old,compute);
        int len=strlen(compute);
        if(len>max && check(compute))
            max=len;
        for(b=0;b<a;b++){
                if(b==i){
                        continue;}
                strcat(compute,arr[b]);
                if(check(compute)){
                int len=strlen(compute);
                        if(len>max)
                        {
                            max=len;
                        }
                    strcpy(old,compute);
                }
                else{
                        strcpy(compute,old);
                }
        }
}
printf("%d",max);

}


#include<stdio.h>
char arr[2000][2000];
int compare(char *q,char *b){
    return *q-*b;
}
int check(char *q){
int a,i;
int cnt=0;
int len=strlen(q);
qsort(q,len,sizeof(char),compare);
for(i=0;i<len;i++){
int temp=q[i];
while(q[i]==temp){
        i++;
}
i--;
cnt++;
}
 if(cnt>2)
    return 0;
 return 1;
}
int main(){
int a,b,c,d;
scanf("%d",&a);
getchar();
int i;
for(i=0;i<a;i++){
        gets(arr[i]);
}
int max=0;
for(i=0;i<a;i++){
        char compute[20000];
        char old[20000];
        strcpy(compute,arr[i]);
        strcpy(old,compute);
        int len=strlen(compute);
        if(len>max && check(compute))
            max=len;
            else if(check(compute)==0)
                    continue;
        for(b=0;b<a;b++){
                if(b==i){
                        continue;}
                strcat(compute,arr[b]);
                if(check(compute)){
                int len=strlen(compute);
                        if(len>max)
                        {
                            max=len;
                        }
                    strcpy(old,compute);
                }
                else{
                        strcpy(compute,old);
                }
        }
}
printf("%d",max);

}


#include<stdio.h>
char arr[2000][2000];
int compare(char *q,char *b){
    int x=strlen(q);
    int y=strlen(b);
    if(x<y)
        return 1;
    else if(x>y)
        return -1;
    else return 0;
}
int comparex(char *q,char *b){
    return *q-*b;
}
int check(char *q){
int a,i;
int cnt=0;
int len=strlen(q);
qsort(q,len,sizeof(char),comparex);
for(i=0;i<len;i++){
int temp=q[i];
while(q[i]==temp){
        i++;
}
i--;
cnt++;
}
 if(cnt>2)
    return 0;
 return 1;
}
int main(){
int a,b,c,d;
scanf("%d",&a);
getchar();
int i;
for(i=0;i<a;i++){
        gets(arr[i]);
}
int max=0;
qsort(arr,a,2000,compare);
for(i=0;i<a;i++){
        char compute[20000];
        char old[20000];
        strcpy(compute,arr[i]);
        strcpy(old,compute);
        int len=strlen(compute);
        if(len>max && check(compute))
            max=len;
            else if(check(compute)==0)
                    continue;
        for(b=0;b<a;b++){
                if(b==i){
                continue;}
                strcat(compute,arr[b]);
                if(check(compute)){
                int len=strlen(compute);
                        if(len>max)
                        {
                            max=len;
                        }
                    strcpy(old,compute);
                }
                else{
                        strcpy(compute,old);
                }
        }
}
printf("%d",max);

}


#include<stdio.h>
char arr[2000][2000];
int cmp(char *q,char a,char b){
 while(*q){
        if(*q!=a && *q!=b)
        return 0;
        q++;
 }
 return 1;
}
int main(){
    int a,b,c,d;
    scanf("%d",&a);getchar();
    int i;
    for(i=0;i<a;i++){
            gets(arr[i]);
    }
    int max=0;
    int cnt=0;
    for(i='a';i<='z';i++){
            for(b='a';b<='z';b++){
                    for(c=0;c<a;c++){
                            if(cmp(arr[c],i,b)){
                                cnt=cnt+strlen(arr[c]);
                            }
            }
            if(cnt>max)
                max=cnt;
            cnt=0;
    }
    }
    printf("%d",max);
}


#include<stdio.h>
char arr[2000][2000];
int compare(char *q,char *b){
    int x=strlen(q);
    int y=strlen(b);
    if(x<y)
        return 1;
    else if(x>y)
        return -1;
    else return 0;
}
int check(char *q){
int a,i;
int cnt=0;
int len=strlen(q);
qsort(q,len,sizeof(char),compare);
for(i=0;i<len;i++){
int temp=q[i];
while(q[i]==temp){
        i++;
}
i--;
cnt++;
}
 if(cnt>2)
    return 0;
 return 1;
}
int main(){
int a,b,c,d;
scanf("%d",&a);
getchar();
int i;
for(i=0;i<a;i++){
        gets(arr[i]);
}
int max=0;
qsort(arr,a,2000,compare);
for(i=0;i<a;i++){
        char compute[20000];
        char old[20000];
        strcpy(compute,arr[i]);
        strcpy(old,compute);
        int len=strlen(compute);
        if(len>max && check(compute))
            max=len;
            else if(check(compute)==0)
                    continue;
        for(b=0;b<a;b++){
                if(b==i){
                continue;}
                strcat(compute,arr[b]);
                if(check(compute)){
                int len=strlen(compute);
                        if(len>max)
                        {
                            max=len;
                        }
                    strcpy(old,compute);
                }
                else{
                        strcpy(compute,old);
                }
        }
}
printf("%d",max);

}


#include <stdio.h>
#include <string.h>

int main(void) {
    int n = 0, i = 0, j = 0, k = 0, l = 0;
    int max_leng = 0, poss = 0, sum = 0;
    char str[1001] = {0, }, *p = 0;
    int cnt[100][26] = {0, };

    scanf("%d", &n);
    for (i=0;i<n;i++) {
        scanf("%s", str);
        p = str;
        while (*p) {
            cnt[i][*p - 'a']++;
            p++;
        }
    }

    for (i=0;i<26;i++) {
        for (j=i+1;j<26;j++) {
            sum = 0;
            for (k=0;k<n;k++) {
                poss = 1;
                int len = 0;
                for (l=0;l<26;l++) {
                    if (l != i && l != j && cnt[k][l] > 0) {
                        poss = 0;
                        break;
                    }
                    len += cnt[k][l];
                }

                if (poss) {
                    sum += len;
                }
            }

            if (max_leng < sum) {
                max_leng = sum;
            }
        }
    }

    printf("%d\n", max_leng);

    return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// type
typedef struct l{
	char c;
	int freq;
}letter_type;

int lettChecks(char *str){
	int c,d;
	char let[50];
	int lcnt = 0;
	int insert = 0;
	for(c =0; c< strlen(str); c++){
		insert = 1;
		for(d=0; d < lcnt; d++){
			if(let[d] == str[c]){
				insert = 0;
				break;
			}
		}
		if(insert == 1){
			let[lcnt++] = str[c];
			if(lcnt > 2)
				return 0;
		}
	}
	return 1;
}

int onlyChars(char *str, char c1, char c2){
	int i;
	for(i = 0; i<strlen(str); i++){
		if(str[i] != c1){
			if (str[i] != c2){
				//printf("TORNO FALSO: %s %c %c\n", str, c1, c2);
				return 0;
			}
		}
	}
	//printf("TORNO VERO: %s %c %c\n", str, c1, c2);

	return 1;
}

int main(){
	int lcnt = 0, d;
	int words;
	int i;
	int j, k;
	int insert = 0;
	int f =0;

	char article[100][1005];
	int wlen[100];
	int wall[100];
	int rank = 0, rank_max = -1;

	letter_type letters[50];

	// read words
	scanf("%d", &words);
	for(i=0; i<words; i++){
		scanf("%s", article[i]);
		wlen[i] = strlen(article[i]);
		if( lettChecks(article[i]) ){
			wall[i] = 1;
		} else {
			wall[i] = 0;
		}
	}

	/*for(i=0; i<words; i++){
		printf("word[%d]: %s, LENGTH= %d, ALLOWED=%d\n",i,article[i], wlen[i], wall[i] );
	}*/

	for(i = 0; i<words; i++){
		if(wall[i]){
			// count letter frequeny
			for(j=0; j<strlen(article[i]); j++){
				insert = 1;
				for(d=0; d < lcnt; d++){
					if(letters[d].c == article[i][j]){
						insert = 0;
						break;
					}
				}
				if(insert == 1){
					letters[lcnt].c = article[i][j];
					letters[lcnt++].freq = 1;
				} else {
					letters[d].freq++;
				}
			}
		}
	}

	/*for(i = 0; i< lcnt; i++){
		printf("Letter: %c, freq: %d\n", letters[i].c, letters[i].freq);
	}*/

	// brute force!
	for(i=0; i<lcnt; i++){
		for(j=i+1; j<lcnt; j++){
			rank = 0;
			for(k=0; k<words; k++){

				if(wall[k]){
					if(onlyChars(article[k], letters[i].c, letters[j].c)){
						rank += wlen[k];
					}
				}
			}
			//printf("Rank for %c %c: %d\n", letters[i].c, letters[j].c, rank);
			if(rank > rank_max){
				rank_max = rank;

			}
		}
	}

	if(rank_max == -1 || rank_max == 0) printf("0");
	else printf("%d",rank_max);

	return 0;
}


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// type
typedef struct l{
	char c;
	int freq;
}letter_type;

int lettChecks(char *str){
	int c,d;
	char let[50];
	int lcnt = 0;
	int insert = 0;
	for(c =0; c< strlen(str); c++){
		insert = 1;
		for(d=0; d < lcnt; d++){
			if(let[d] == str[c]){
				insert = 0;
				break;
			}
		}
		if(insert == 1){
			let[lcnt++] = str[c];
			if(lcnt > 2)
				return 0;
		}
	}
	return 1;
}

int onlyChars(char *str, char c1, char c2){
	int i;
	for(i = 0; i<strlen(str); i++){
		if(str[i] != c1){
			if (str[i] != c2){
				printf("TORNO FALSO: %s %c %c\n", str, c1, c2);
				return 0;
			}
		}
	}
	printf("TORNO VERO: %s %c %c\n", str, c1, c2);

	return 1;
}

int main(){
	int lcnt = 0, d;
	int words;
	int i;
	int j, k;
	int insert = 0;
	int f =0;

	char article[100][1005];
	int wlen[100];
	int wall[100];
	int rank = 0, rank_max = -1;

	letter_type letters[50];

	// read words
	scanf("%d", &words);
	for(i=0; i<words; i++){
		scanf("%s", article[i]);
		wlen[i] = strlen(article[i]);
		if( lettChecks(article[i]) ){
			wall[i] = 1;
		} else {
			wall[i] = 0;
		}
	}

	/*for(i=0; i<words; i++){
		printf("word[%d]: %s, LENGTH= %d, ALLOWED=%d\n",i,article[i], wlen[i], wall[i] );
	}*/

	for(i = 0; i<words; i++){
		if(wall[i]){
			// count letter frequeny
			for(j=0; j<strlen(article[i]); j++){
				insert = 1;
				for(d=0; d < lcnt; d++){
					if(letters[d].c == article[i][j]){
						insert = 0;
						break;
					}
				}
				if(insert == 1){
					letters[lcnt].c = article[i][j];
					letters[lcnt++].freq = 1;
				} else {
					letters[d].freq++;
				}
			}
		}
	}

	/*for(i = 0; i< lcnt; i++){
		printf("Letter: %c, freq: %d\n", letters[i].c, letters[i].freq);
	}*/

	// brute force!
	for(i=0; i<lcnt; i++){
		for(j=i+1; j<lcnt; j++){
			rank = 0;
			for(k=0; k<words; k++){

				if(wall[k]){
					if(onlyChars(article[k], letters[i].c, letters[j].c)){
						rank += wlen[k];
					}
				}
			}
			printf("Rank for %c %c: %d\n", letters[i].c, letters[j].c, rank);
			if(rank > rank_max){
				rank_max = rank;

			}
		}
	}

	if(rank_max == -1) printf("0");
	printf("%d",rank_max);

	return 0;
}


//#pragma GCC optimize("Ofast")
//#pragma GCC optimization ("O3")
//#pragma GCC optimize ("unroll-loops")
//#pragma GCC target("avx,avx2,fma")
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
#define mod 1000000007
#define fi first
#define se second
#define pii pair<int,int>
//#define push_back emplace_back
//#define push emplace
//#define insert emplace
#define int long long
#define endl '\n'
#define pll pair<long long,long long>
#define LONGLONG_MAX 10000000000000000
using namespace std;
template <typename T>
using ordered_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;
long long power(long long a,long long b){
    long long ans=1;
    while(b>0){
        if(b&1){ans=(ans*a)%mod;}
                a=(a*a)%mod;
                b>>=1;
        }
    return ans;

}

int32_t main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	int n;
	cin>>n;
	int d[n][n];
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){
			cin>>d[i][j];
		}
	}
	int a[n];
	for(int i=0;i<n;i++){
		a[i]=d[0][i];
	}
	sort(a,a+n);
	for(int i=0;i<n;i++){
		for(int j=0;j<n;j++){

			if(i==j){
				if(d[i][j]!=0){
					cout<<"NO";return 0;
				}
				continue;
			}
			if(d[i][j]==0||d[i][j]!=d[j][i]){
				cout<<"NO";return 0;
			}
			if(!binary_search(a,a+n,(d[0][i]+d[0][j]-d[i][j])/2)||(d[0][i]+d[0][j]-d[i][j])%2==1){
				cout<<"NO";return 0;
			}
		}
	}
	cout<<"YES";
	return 0;

}


// g++ -std=c++14

/*

Today might be the chance to grasp the chance to let your talent bloom.
May be tomorrow, the day after, or next year...
May be even when you are 30. I'm not sure if physique has anything to do with it
but if you think that it will never come, it probably never will.

- Tooru Oikawa.

*/

#include<bits/stdc++.h>

typedef long long ll;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x)
#define sd2(x,y) scanf("%d%d",&x,&y)
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define endl "\n"
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#define all(c) c.begin(),c.end()
#define inf INT_MAX

#define tr(...) cout<<__FUNCTION__<<' '<<__LINE__<<" = ";trace(#__VA_ARGS__, __VA_ARGS__)

template<typename S, typename T>
ostream& operator<<(ostream& out,pair<S,T> const& p){out<<'('<<p.fi<<", "<<p.se<<')';return out;}

template<typename T>
ostream& operator<<(ostream& out,vector<T> const& v){
ll l=v.size();for(ll i=0;i<l-1;i++)out<<v[i]<<' ';if(l>0)out<<v[l-1];return out;}

template<typename T>
void trace(const char* name, T&& arg1){cout<<name<<" : "<<arg1<<endl;}

template<typename T, typename... Args>
void trace(const char* names, T&& arg1, Args&&... args){
const char* comma = strchr(names + 1, ',');cout.write(names, comma-names)<<" : "<<arg1<<" | ";trace(comma+1,args...);}

// #define int ll

#define no printf("NO\n");

const int N = 2010;

int parent[N];
int size[N];

int n, d[N][N];
vector<vector<pair<int, int> > > g(N);

void make_set(int x){
    parent[x] = x;
    size[x] = 1;
}

int find_set(int v){
    if(v==parent[v]){
        return v;
    }
    return parent[v] =find_set(parent[v]);
}

void union_sets(int a,int b){
    a = find_set(a);
    b = find_set(b);
    if(a!=b){
        if(size[a]<size[b]){
            swap(a,b);
        }
        parent[b] = a;
        size[a] += size[b];
    }
}

void validate(){
    for(int i = 1; i <= n; i++){
        if(d[i][i] != 0){
            no
            exit(0);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(d[i][j] != d[j][i]){
                no
                exit(0);
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i != j and d[i][j] == 0){
                no
                exit(0);
            }
        }
    }
}

bool check(int s){
    vector<int> dist(n + 1, inf);
    set<pair<int,int> > q;
    dist[s] = 0;
    q.insert(mp(dist[s],s));
    while(!q.empty()){
        int v = (*q.begin()).se;
        int v_d = (*q.begin()).fi;
        q.erase(q.begin());
        for(auto t:g[v]){
            int to = t.se;
            int weight = t.fi;
            int get_out = v_d + weight;
            if(get_out<dist[to]){
                dist[to] = get_out;
                q.insert(mp(get_out,to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(d[s][i] != dist[i]){
            return false;
        }
    }
    return true;
}

int32_t main(){
    sd(n);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            sd(d[i][j]);
        }
    }
    validate();
    for(int i = 1; i <= n; i++){
        make_set(i);
    }
    set<pair<int, pair<int, int> > > s;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            s.insert(mp(d[i][j], mp(i, j)));
        }
    }
    int taken = 0;
    while(!s.empty() and taken < (n - 1)){
        auto top = *(s.begin());
        // tr(top);
        s.erase(s.begin());
        int dist = top.fi;

        int u = top.se.fi, v = top.se.se;
        if(u != v){
            s.erase(mp(dist, mp(v, u)));
        }
        if(find_set(u) == find_set(v)){
            continue;
        }
        union_sets(u, v);
        g[u].pb(mp(dist, v));
        g[v].pb(mp(dist, u));
        taken++;
    }
    // for(int i = 1; i <= n; i++){
    //     tr(i, g[i]);
    // }
    for(int i = 1; i <= n; i++){
        if(!check(i)){
            printf("NO\n");
            return 0;
        }
    }
    printf("YES\n");
    return 0;
}


// g++ -std=c++14
#include<bits/stdc++.h>
typedef long long int lli;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x);
#define sd2(x,y) scanf("%d%d",&x,&y);
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z);

#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define all(c) c.begin(),c.end()

#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
vector<vector<lli> >mat;
bool poss;
vector<pair<int,int> >edg;
vector<bool>taken;
struct cmp{
  bool operator()(const pair<int,int>& lhs, const pair<int,int>& rhs){
    return mat[lhs.fi][lhs.se] > mat[rhs.fi][rhs.se];
  }
};
int main(){
  _
  int n;
  cin >> n;
  poss = true;
  lli Min = 1000000009;
  mat.resize(n,vector<lli>(n));
  taken.resize(n,false);
  int u = -1, v = -1;
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      cin >> mat[i][j];
      if(i!=j and Min>mat[i][j]){
        Min = mat[i][j];
        u = i;
        v = j;
        if(mat[i][j]==0){
          poss = false;
        }
      }
    }
  }
  edg.pb(make_pair(u,v));
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      if(i==j and mat[i][j]!=0){
        poss = false;
        break;
      }
      if(mat[i][j]!=mat[j][i]){
        poss = false;
        break;
      }
    }
  }
  if(!poss){
    cout << "NO\n";
    return 0;
  }
  priority_queue<pair<int,int>,vector<pair<int,int> >, cmp >pq;
  while(edg.size()<n-1){
    int u = edg[edg.size()-1].fi;
    int v = edg[edg.size()-1].se;
    for(int i=0;i<n;i++){
      if(i!=u and i!=v and !taken[u] and !taken[i]){
        pq.push(mp(u,i));
      }
      if(i!=v and i!=u and !taken[v] and !taken[i]){
        pq.push(mp(v,i));
      }
    }
    taken[u] = true;
    taken[v] = true;
    // cout << "aa " << u << " " << v << "\n";
    pair<int,int> pii = pq.top();
    pq.pop();
    edg.pb(make_pair(pii.fi,pii.se));
    int newNode;
    int oldNode;
    if(!taken[pii.fi]){
      newNode = pii.fi;
      oldNode = pii.se;
    }
    else{
      newNode = pii.se;
      oldNode = pii.fi;
    }
    // cout << newNode << " " << oldNode << "\n";
    for(int i=0;i<n;i++){
      if(i!=newNode and taken[i]){
        if(!(mat[i][newNode]==mat[i][oldNode]+mat[oldNode][newNode] or mat[i][oldNode]==mat[i][newNode]+mat[oldNode][newNode])){
          // cout << newNode << " " << oldNode << " " << i << "\n";
          poss = false;
          break;
        }
      }
    }
  }
  // cout << "comehere\n";
  if(poss){
    cout << "YES\n";
  }
  else{
    cout << "NO\n";
  }
  return 0;
}


// g++ -std=c++14

/*

Today might be the chance to grasp the chance to let your talent bloom.
May be tomorrow, the day after, or next year...
May be even when you are 30. I'm not sure if physique has anything to do with it
but if you think that it will never come, it probably never will.

- Tooru Oikawa.

*/

#include<bits/stdc++.h>

typedef long long ll;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x)
#define sd2(x,y) scanf("%d%d",&x,&y)
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define endl "\n"
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#define all(c) c.begin(),c.end()
#define inf 1000000000000000001

#define tr(...) cout<<__FUNCTION__<<' '<<__LINE__<<" = ";trace(#__VA_ARGS__, __VA_ARGS__)

template<typename S, typename T>
ostream& operator<<(ostream& out,pair<S,T> const& p){out<<'('<<p.fi<<", "<<p.se<<')';return out;}

template<typename T>
ostream& operator<<(ostream& out,vector<T> const& v){
ll l=v.size();for(ll i=0;i<l-1;i++)out<<v[i]<<' ';if(l>0)out<<v[l-1];return out;}

template<typename T>
void trace(const char* name, T&& arg1){cout<<name<<" : "<<arg1<<endl;}

template<typename T, typename... Args>
void trace(const char* names, T&& arg1, Args&&... args){
const char* comma = strchr(names + 1, ',');cout.write(names, comma-names)<<" : "<<arg1<<" | ";trace(comma+1,args...);}

#define int ll

const int N = 2010;

ll parent[N];
ll size[N];

int n, d[N][N];
vector<vector<pair<int, int> > > g(N);

void make_set(ll x){
    parent[x] = x;
    size[x] = 1;
}

ll find_set(ll v){
    if(v==parent[v]){
        return v;
    }
    return parent[v] =find_set(parent[v]);
}

void union_sets(ll a,ll b){
    a = find_set(a);
    b = find_set(b);
    if(a!=b){
        if(size[a]<size[b]){
            swap(a,b);
        }
        parent[b] = a;
        size[a] += size[b];
    }
}

void validate(){
    for(int i = 1; i <= n; i++){
        if(d[i][i] != 0){
            cout << "NO\n";
            exit(0);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(d[i][j] != d[j][i]){
                cout << "NO\n";
                exit(0);
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i != j and d[i][j] == 0){
                cout << "NO\n";
                exit(0);
            }
        }
    }
}

bool check(int s){
    vector<int> dist(n + 1, inf);
    set<pair<ll,ll> > q;
    dist[s] = 0;
    q.insert(mp(dist[s],s));
    while(!q.empty()){
        ll v = (*q.begin()).se;
        ll v_d = (*q.begin()).fi;
        q.erase(q.begin());
        for(auto t:g[v]){
            ll to = t.se;
            ll weight = t.fi;
            ll get_out = v_d + weight;
            if(get_out<dist[to]){
                dist[to] = get_out;
                q.insert(mp(get_out,to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(d[s][i] != dist[i]){
            return false;
        }
    }
    return true;
}

int32_t main(){ _
    cin >> n;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cin >> d[i][j];
        }
    }
    validate();
    for(int i = 1; i <= n; i++){
        make_set(i);
    }
    set<pair<int, pair<int, int> > > s;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            s.insert(mp(d[i][j], mp(i, j)));
        }
    }
    int taken = 0;
    while(!s.empty() and taken < (n - 1)){
        auto top = *(s.begin());
        // tr(top);
        s.erase(s.begin());
        int dist = top.fi;
        int u = top.se.fi, v = top.se.se;
        s.erase(mp(dist, mp(v, u)));
        if(find_set(u) == find_set(v)){
            continue;
        }
        g[u].pb(mp(dist, v));
        g[v].pb(mp(dist, u));
        taken++;
    }
    // for(int i = 1; i <= n; i++){
    //     tr(i, g[i]);
    // }
    for(int i = 1; i <= n; i++){
        if(!check(i)){
            cout << "NO\n";
            return 0;
        }
    }
    cout << "YES\n";
    return 0;
}


// g++ -std=c++14

/*

Today might be the chance to grasp the chance to let your talent bloom.
May be tomorrow, the day after, or next year...
May be even when you are 30. I'm not sure if physique has anything to do with it
but if you think that it will never come, it probably never will.

- Tooru Oikawa.

*/

#include<bits/stdc++.h>

typedef long long ll;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x)
#define sd2(x,y) scanf("%d%d",&x,&y)
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define endl "\n"
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#define all(c) c.begin(),c.end()
#define inf 1000000000000000001

#define tr(...) cout<<__FUNCTION__<<' '<<__LINE__<<" = ";trace(#__VA_ARGS__, __VA_ARGS__)

template<typename S, typename T>
ostream& operator<<(ostream& out,pair<S,T> const& p){out<<'('<<p.fi<<", "<<p.se<<')';return out;}

template<typename T>
ostream& operator<<(ostream& out,vector<T> const& v){
ll l=v.size();for(ll i=0;i<l-1;i++)out<<v[i]<<' ';if(l>0)out<<v[l-1];return out;}

template<typename T>
void trace(const char* name, T&& arg1){cout<<name<<" : "<<arg1<<endl;}

template<typename T, typename... Args>
void trace(const char* names, T&& arg1, Args&&... args){
const char* comma = strchr(names + 1, ',');cout.write(names, comma-names)<<" : "<<arg1<<" | ";trace(comma+1,args...);}

#define int ll

const int N = 2010;

ll parent[N];
ll size[N];

int n, d[N][N];
vector<vector<pair<int, int> > > g(N);

void make_set(ll x){
    parent[x] = x;
    size[x] = 1;
}

ll find_set(ll v){
    if(v==parent[v]){
        return v;
    }
    return parent[v] =find_set(parent[v]);
}

void union_sets(ll a,ll b){
    a = find_set(a);
    b = find_set(b);
    if(a!=b){
        if(size[a]<size[b]){
            swap(a,b);
        }
        parent[b] = a;
        size[a] += size[b];
    }
}

void validate(){
    for(int i = 1; i <= n; i++){
        if(d[i][i] != 0){
            cout << "NO\n";
            exit(0);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(d[i][j] != d[j][i]){
                cout << "NO\n";
                exit(0);
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i != j and d[i][j] == 0){
                cout << "NO\n";
                exit(0);
            }
        }
    }
}

bool check(int s){
    vector<int> dist(n + 1, inf);
    set<pair<ll,ll> > q;
    dist[s] = 0;
    q.insert(mp(dist[s],s));
    while(!q.empty()){
        ll v = (*q.begin()).se;
        ll v_d = (*q.begin()).fi;
        q.erase(q.begin());
        for(auto t:g[v]){
            ll to = t.se;
            ll weight = t.fi;
            ll get_out = v_d + weight;
            if(get_out<dist[to]){
                dist[to] = get_out;
                q.insert(mp(get_out,to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(d[s][i] != dist[i]){
            return false;
        }
    }
    return true;
}

int32_t main(){ _
    cin >> n;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cin >> d[i][j];
        }
    }
    validate();
    for(int i = 1; i <= n; i++){
        make_set(i);
    }
    set<pair<int, pair<int, int> > > s;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            s.insert(mp(d[i][j], mp(i, j)));
        }
    }
    int taken = 0;
    while(!s.empty() and taken < (n - 1)){
        auto top = *(s.begin());
        // tr(top);
        s.erase(s.begin());
        int dist = top.fi;

        int u = top.se.fi, v = top.se.se;
        if(u != v){
            s.erase(mp(dist, mp(v, u)));
        }
        if(find_set(u) == find_set(v)){
            continue;
        }
        g[u].pb(mp(dist, v));
        g[v].pb(mp(dist, u));
        taken++;
    }
    // for(int i = 1; i <= n; i++){
    //     tr(i, g[i]);
    // }
    for(int i = 1; i <= n; i++){
        if(!check(i)){
            cout << "NO\n";
            return 0;
        }
    }
    cout << "YES\n";
    return 0;
}


// g++ -std=c++14
#include<bits/stdc++.h>
typedef long long int lli;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x);
#define sd2(x,y) scanf("%d%d",&x,&y);
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z);

#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define all(c) c.begin(),c.end()

#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
vector<vector<lli> >mat;
bool poss;
vector<pair<int,int> >edg;
vector<bool>taken;
struct cmp{
  bool operator()(const pair<int,int>& lhs, const pair<int,int>& rhs){
    return mat[lhs.fi][lhs.se] > mat[rhs.fi][rhs.se];
  }
};
int main(){
  _
  int n;
  cin >> n;
  poss = true;
  lli Min = 1000000009;
  mat.resize(n,vector<lli>(n));
  taken.resize(n,false);
  int u = -1, v = -1;
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      cin >> mat[i][j];
      if(i!=j and Min>mat[i][j]){
        Min = mat[i][j];
        u = i;
        v = j;
        if(mat[i][j]==0){
          poss = false;
        }
      }
    }
  }
  edg.pb(make_pair(u,v));
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      if(i==j and mat[i][j]!=0){
        poss = false;
        break;
      }
      if(mat[i][j]!=mat[j][i]){
        poss = false;
        break;
      }
    }
  }
  if(!poss){
    cout << "NO\n";
    return 0;
  }
  priority_queue<pair<int,int>,vector<pair<int,int> >, cmp >pq;
  while(edg.size()<n-1){
    int u = edg[edg.size()-1].fi;
    int v = edg[edg.size()-1].se;
    for(int i=0;i<n;i++){
      if(i!=u and i!=v and !taken[u] and !taken[i]){
        pq.push(mp(u,i));
      }
      if(i!=v and i!=u and !taken[v] and !taken[i]){
        pq.push(mp(v,i));
      }
    }
    taken[u] = true;
    taken[v] = true;
    // cout << "aa " << u << " " << v << "\n";
    pair<int,int> pii = pq.top();
    pq.pop();
    edg.pb(make_pair(pii.fi,pii.se));
    int newNode;
    int oldNode;
    if(!taken[pii.fi]){
      newNode = pii.fi;
      oldNode = pii.se;
    }
    else{
      newNode = pii.se;
      oldNode = pii.fi;
    }
    // cout << newNode << " " << oldNode << "\n";
    for(int i=0;i<n;i++){
      if(i!=newNode and taken[i]){
        if(mat[i][newNode]!=mat[i][oldNode]+mat[oldNode][newNode]){
          // cout << newNode << " " << oldNode << " " << i << "\n";
          poss = false;
          break;
        }
      }
    }
  }
  // cout << "comehere\n";
  if(poss){
    cout << "YES\n";
  }
  else{
    cout << "NO\n";
  }
  return 0;
}


// g++ -std=c++14

/*

Today might be the chance to grasp the chance to let your talent bloom.
May be tomorrow, the day after, or next year...
May be even when you are 30. I'm not sure if physique has anything to do with it
but if you think that it will never come, it probably never will.

- Tooru Oikawa.

*/

#include<bits/stdc++.h>

typedef long long ll;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x)
#define sd2(x,y) scanf("%d%d",&x,&y)
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define endl "\n"
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#define all(c) c.begin(),c.end()
#define inf INT_MAX

#define tr(...) cout<<__FUNCTION__<<' '<<__LINE__<<" = ";trace(#__VA_ARGS__, __VA_ARGS__)

template<typename S, typename T>
ostream& operator<<(ostream& out,pair<S,T> const& p){out<<'('<<p.fi<<", "<<p.se<<')';return out;}

template<typename T>
ostream& operator<<(ostream& out,vector<T> const& v){
ll l=v.size();for(ll i=0;i<l-1;i++)out<<v[i]<<' ';if(l>0)out<<v[l-1];return out;}

template<typename T>
void trace(const char* name, T&& arg1){cout<<name<<" : "<<arg1<<endl;}

template<typename T, typename... Args>
void trace(const char* names, T&& arg1, Args&&... args){
const char* comma = strchr(names + 1, ',');cout.write(names, comma-names)<<" : "<<arg1<<" | ";trace(comma+1,args...);}

// #define int ll

#define no printf("NO\n");

const int N = 2010;

int parent[N];
int size[N];

int n, d[N][N];
vector<vector<pair<int, int> > > g(N);

void make_set(int x){
    parent[x] = x;
    size[x] = 1;
}

int find_set(int v){
    if(v==parent[v]){
        return v;
    }
    return parent[v] =find_set(parent[v]);
}

void union_sets(int a,int b){
    a = find_set(a);
    b = find_set(b);
    if(a!=b){
        if(size[a]<size[b]){
            swap(a,b);
        }
        parent[b] = a;
        size[a] += size[b];
    }
}

void validate(){
    for(int i = 1; i <= n; i++){
        if(d[i][i] != 0){
            no
            exit(0);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(d[i][j] != d[j][i]){
                no
                exit(0);
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i != j and d[i][j] == 0){
                no
                exit(0);
            }
        }
    }
}

bool check(int s){
    vector<int> dist(n + 1, inf);
    priority_queue<pair<int, int>, vector<pair<int, int> > > q;
    dist[s] = 0;
    q.push(mp(-dist[s],s));
    while(!q.empty()){
        auto temp = q.top();
        int v = temp.se;
        int v_d = -temp.fi;
        q.pop();
        for(auto t:g[v]){
            int to = t.se;
            int weight = t.fi;
            int get_out = v_d + weight;
            if(get_out<dist[to]){
                dist[to] = get_out;
                q.push(mp(-get_out,to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(d[s][i] != dist[i]){
            return false;
        }
    }
    return true;
}

int32_t main(){
    sd(n);
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            sd(d[i][j]);
        }
    }
    validate();
    for(int i = 1; i <= n; i++){
        make_set(i);
    }
    priority_queue<pair<int, pair<int, int> >, vector<pair<int, pair<int, int> > > > s;
    for(int i = 1; i <= n; i++){
        for(int j = i; j <= n; j++){
            s.push(mp(-d[i][j], mp(i, j)));
        }
    }
    int taken = 0;
    while(!s.empty() and taken < (n - 1)){
        auto top = s.top();
        // tr(top);
        s.pop();
        int dist = -top.fi;

        int u = top.se.fi, v = top.se.se;
        if(find_set(u) == find_set(v)){
            continue;
        }
        union_sets(u, v);
        g[u].pb(mp(dist, v));
        g[v].pb(mp(dist, u));
        taken++;
    }
    // for(int i = 1; i <= n; i++){
    //     tr(i, g[i]);
    // }
    for(int i = 1; i <= n; i++){
        if(!check(i)){
            printf("NO\n");
            return 0;
        }
    }
    printf("YES\n");
    return 0;
}


// g++ -std=c++14

/*

Today might be the chance to grasp the chance to let your talent bloom.
May be tomorrow, the day after, or next year...
May be even when you are 30. I'm not sure if physique has anything to do with it
but if you think that it will never come, it probably never will.

- Tooru Oikawa.

*/

#include<bits/stdc++.h>

typedef long long ll;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x)
#define sd2(x,y) scanf("%d%d",&x,&y)
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define endl "\n"
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#define all(c) c.begin(),c.end()
#define inf 1000000000000000001

#define tr(...) cout<<__FUNCTION__<<' '<<__LINE__<<" = ";trace(#__VA_ARGS__, __VA_ARGS__)

template<typename S, typename T>
ostream& operator<<(ostream& out,pair<S,T> const& p){out<<'('<<p.fi<<", "<<p.se<<')';return out;}

template<typename T>
ostream& operator<<(ostream& out,vector<T> const& v){
ll l=v.size();for(ll i=0;i<l-1;i++)out<<v[i]<<' ';if(l>0)out<<v[l-1];return out;}

template<typename T>
void trace(const char* name, T&& arg1){cout<<name<<" : "<<arg1<<endl;}

template<typename T, typename... Args>
void trace(const char* names, T&& arg1, Args&&... args){
const char* comma = strchr(names + 1, ',');cout.write(names, comma-names)<<" : "<<arg1<<" | ";trace(comma+1,args...);}

#define int ll

const int N = 2010;

ll parent[N];
ll size[N];

int n, d[N][N];
vector<vector<pair<int, int> > > g(N);

void make_set(ll x){
    parent[x] = x;
    size[x] = 1;
}

ll find_set(ll v){
    if(v==parent[v]){
        return v;
    }
    return parent[v] =find_set(parent[v]);
}

void union_sets(ll a,ll b){
    a = find_set(a);
    b = find_set(b);
    if(a!=b){
        if(size[a]<size[b]){
            swap(a,b);
        }
        parent[b] = a;
        size[a] += size[b];
    }
}

void validate(){
    for(int i = 1; i <= n; i++){
        if(d[i][i] != 0){
            cout << "NO\n";
            exit(0);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(d[i][j] != d[j][i]){
                cout << "NO\n";
                exit(0);
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i != j and d[i][j] == 0){
                cout << "NO\n";
                exit(0);
            }
        }
    }
}

bool check(int s){
    vector<int> dist(n + 1, inf);
    set<pair<ll,ll> > q;
    dist[s] = 0;
    q.insert(mp(dist[s],s));
    while(!q.empty()){
        ll v = (*q.begin()).se;
        ll v_d = (*q.begin()).fi;
        q.erase(q.begin());
        for(auto t:g[v]){
            ll to = t.se;
            ll weight = t.fi;
            ll get_out = v_d + weight;
            if(get_out<dist[to]){
                dist[to] = get_out;
                q.insert(mp(get_out,to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(d[s][i] != dist[i]){
            return false;
        }
    }
    return true;
}

int32_t main(){ _
    cin >> n;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cin >> d[i][j];
        }
    }
    validate();
    for(int i = 1; i <= n; i++){
        make_set(i);
    }
    set<pair<int, pair<int, int> > > s;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            s.insert(mp(d[i][j], mp(i, j)));
        }
    }
    int taken = 0;
    while(!s.empty() and taken < (n - 1)){
        auto top = *(s.begin());
        // tr(top);
        s.erase(s.begin());
        int dist = top.fi;

        int u = top.se.fi, v = top.se.se;
        if(u != v){
            s.erase(mp(dist, mp(v, u)));
        }
        if(find_set(u) == find_set(v)){
            continue;
        }
        union_sets(u, v);
        g[u].pb(mp(dist, v));
        g[v].pb(mp(dist, u));
        taken++;
    }
    // for(int i = 1; i <= n; i++){
    //     tr(i, g[i]);
    // }
    for(int i = 1; i <= n; i++){
        if(!check(i)){
            cout << "NO\n";
            return 0;
        }
    }
    cout << "YES\n";
    return 0;
}


// g++ -std=c++14

/*

Today might be the chance to grasp the chance to let your talent bloom.
May be tomorrow, the day after, or next year...
May be even when you are 30. I'm not sure if physique has anything to do with it
but if you think that it will never come, it probably never will.

- Tooru Oikawa.

*/

#include<bits/stdc++.h>

typedef long long ll;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x)
#define sd2(x,y) scanf("%d%d",&x,&y)
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define endl "\n"
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#define all(c) c.begin(),c.end()
#define inf 1000000000000000001

#define tr(...) cout<<__FUNCTION__<<' '<<__LINE__<<" = ";trace(#__VA_ARGS__, __VA_ARGS__)

template<typename S, typename T>
ostream& operator<<(ostream& out,pair<S,T> const& p){out<<'('<<p.fi<<", "<<p.se<<')';return out;}

template<typename T>
ostream& operator<<(ostream& out,vector<T> const& v){
ll l=v.size();for(ll i=0;i<l-1;i++)out<<v[i]<<' ';if(l>0)out<<v[l-1];return out;}

template<typename T>
void trace(const char* name, T&& arg1){cout<<name<<" : "<<arg1<<endl;}

template<typename T, typename... Args>
void trace(const char* names, T&& arg1, Args&&... args){
const char* comma = strchr(names + 1, ',');cout.write(names, comma-names)<<" : "<<arg1<<" | ";trace(comma+1,args...);}

// #define int ll

const int N = 2010;

int parent[N];
int size[N];

int n, d[N][N];
vector<vector<pair<int, int> > > g(N);

void make_set(int x){
    parent[x] = x;
    size[x] = 1;
}

int find_set(int v){
    if(v==parent[v]){
        return v;
    }
    return parent[v] =find_set(parent[v]);
}

void union_sets(int a,int b){
    a = find_set(a);
    b = find_set(b);
    if(a!=b){
        if(size[a]<size[b]){
            swap(a,b);
        }
        parent[b] = a;
        size[a] += size[b];
    }
}

void validate(){
    for(int i = 1; i <= n; i++){
        if(d[i][i] != 0){
            cout << "NO\n";
            exit(0);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(d[i][j] != d[j][i]){
                cout << "NO\n";
                exit(0);
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i != j and d[i][j] == 0){
                cout << "NO\n";
                exit(0);
            }
        }
    }
}

bool check(int s){
    vector<int> dist(n + 1, inf);
    set<pair<int,int> > q;
    dist[s] = 0;
    q.insert(mp(dist[s],s));
    while(!q.empty()){
        int v = (*q.begin()).se;
        int v_d = (*q.begin()).fi;
        q.erase(q.begin());
        for(auto t:g[v]){
            int to = t.se;
            int weight = t.fi;
            int get_out = v_d + weight;
            if(get_out<dist[to]){
                dist[to] = get_out;
                q.insert(mp(get_out,to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(d[s][i] != dist[i]){
            return false;
        }
    }
    return true;
}

int32_t main(){ _
    cin >> n;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cin >> d[i][j];
        }
    }
    validate();
    for(int i = 1; i <= n; i++){
        make_set(i);
    }
    set<pair<int, pair<int, int> > > s;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            s.insert(mp(d[i][j], mp(i, j)));
        }
    }
    int taken = 0;
    while(!s.empty() and taken < (n - 1)){
        auto top = *(s.begin());
        // tr(top);
        s.erase(s.begin());
        int dist = top.fi;

        int u = top.se.fi, v = top.se.se;
        if(u != v){
            s.erase(mp(dist, mp(v, u)));
        }
        if(find_set(u) == find_set(v)){
            continue;
        }
        union_sets(u, v);
        g[u].pb(mp(dist, v));
        g[v].pb(mp(dist, u));
        taken++;
    }
    // for(int i = 1; i <= n; i++){
    //     tr(i, g[i]);
    // }
    for(int i = 1; i <= n; i++){
        if(!check(i)){
            cout << "NO\n";
            return 0;
        }
    }
    cout << "YES\n";
    return 0;
}


// g++ -std=c++14

/*

Today might be the chance to grasp the chance to let your talent bloom.
May be tomorrow, the day after, or next year...
May be even when you are 30. I'm not sure if physique has anything to do with it
but if you think that it will never come, it probably never will.

- Tooru Oikawa.

*/

#include<bits/stdc++.h>

typedef long long ll;
typedef long double lld;
using namespace std;

#define sd(x) scanf("%d",&x)
#define sd2(x,y) scanf("%d%d",&x,&y)
#define sd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define endl "\n"
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define LET(x, a)  __typeof(a) x(a)
#define foreach(it, v) for(LET(it, v.begin()); it != v.end(); it++)
#define MEMS(a,b) memset(a,b,sizeof(a))
#define _ ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define __ freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#define all(c) c.begin(),c.end()
#define inf INT_MAX

#define tr(...) cout<<__FUNCTION__<<' '<<__LINE__<<" = ";trace(#__VA_ARGS__, __VA_ARGS__)

template<typename S, typename T>
ostream& operator<<(ostream& out,pair<S,T> const& p){out<<'('<<p.fi<<", "<<p.se<<')';return out;}

template<typename T>
ostream& operator<<(ostream& out,vector<T> const& v){
ll l=v.size();for(ll i=0;i<l-1;i++)out<<v[i]<<' ';if(l>0)out<<v[l-1];return out;}

template<typename T>
void trace(const char* name, T&& arg1){cout<<name<<" : "<<arg1<<endl;}

template<typename T, typename... Args>
void trace(const char* names, T&& arg1, Args&&... args){
const char* comma = strchr(names + 1, ',');cout.write(names, comma-names)<<" : "<<arg1<<" | ";trace(comma+1,args...);}

// #define int ll

const int N = 2010;

int parent[N];
int size[N];

int n, d[N][N];
vector<vector<pair<int, int> > > g(N);

void make_set(int x){
    parent[x] = x;
    size[x] = 1;
}

int find_set(int v){
    if(v==parent[v]){
        return v;
    }
    return parent[v] =find_set(parent[v]);
}

void union_sets(int a,int b){
    a = find_set(a);
    b = find_set(b);
    if(a!=b){
        if(size[a]<size[b]){
            swap(a,b);
        }
        parent[b] = a;
        size[a] += size[b];
    }
}

void validate(){
    for(int i = 1; i <= n; i++){
        if(d[i][i] != 0){
            cout << "NO\n";
            exit(0);
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(d[i][j] != d[j][i]){
                cout << "NO\n";
                exit(0);
            }
        }
    }
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            if(i != j and d[i][j] == 0){
                cout << "NO\n";
                exit(0);
            }
        }
    }
}

bool check(int s){
    vector<int> dist(n + 1, inf);
    set<pair<int,int> > q;
    dist[s] = 0;
    q.insert(mp(dist[s],s));
    while(!q.empty()){
        int v = (*q.begin()).se;
        int v_d = (*q.begin()).fi;
        q.erase(q.begin());
        for(auto t:g[v]){
            int to = t.se;
            int weight = t.fi;
            int get_out = v_d + weight;
            if(get_out<dist[to]){
                dist[to] = get_out;
                q.insert(mp(get_out,to));
            }
        }
    }
    for(int i = 1; i <= n; i++){
        if(d[s][i] != dist[i]){
            return false;
        }
    }
    return true;
}

int32_t main(){ _
    cin >> n;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            cin >> d[i][j];
        }
    }
    validate();
    for(int i = 1; i <= n; i++){
        make_set(i);
    }
    set<pair<int, pair<int, int> > > s;
    for(int i = 1; i <= n; i++){
        for(int j = 1; j <= n; j++){
            s.insert(mp(d[i][j], mp(i, j)));
        }
    }
    int taken = 0;
    while(!s.empty() and taken < (n - 1)){
        auto top = *(s.begin());
        // tr(top);
        s.erase(s.begin());
        int dist = top.fi;

        int u = top.se.fi, v = top.se.se;
        if(u != v){
            s.erase(mp(dist, mp(v, u)));
        }
        if(find_set(u) == find_set(v)){
            continue;
        }
        union_sets(u, v);
        g[u].pb(mp(dist, v));
        g[v].pb(mp(dist, u));
        taken++;
    }
    // for(int i = 1; i <= n; i++){
    //     tr(i, g[i]);
    // }
    for(int i = 1; i <= n; i++){
        if(!check(i)){
            cout << "NO\n";
            return 0;
        }
    }
    cout << "YES\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return w > rhs.w ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    dep[u] = dep[pre]+1 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,u) ;
        dis[v] = dis[u] + e.y ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int w , int pre )
{
    dep[u] = dep[pre] + 1 ;
    dis[u] = dis[pre] + w ;
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,e.y,u) ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-2*dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    dep[u] = dep[pre] + 1 ;
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dis[v] = dis[u] + e.y ;
        dfs1(v,u) ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-2*dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    node( int u , int v , int w ){ }
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push(node(1,0,0)) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push(node(i,u,a[u][i])) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    dep[u] = dep[pre]+1 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,u) ;
        dis[v] = dis[u] + e.y ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int w , int pre )
{
    dep[u] = dep[pre] + 1 ;
    dis[u] = dis[pre] + w ;
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,w,u) ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-2*dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return w > rhs.w ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            cout << u << ' ' << v << endl ;
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    dep[u] = dep[pre]+1 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,u) ;
        dis[v] = dis[u] + e.y ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return w > rhs.w ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] >= a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    dep[u] = dep[pre]+1 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,u) ;
        dis[v] = dis[u] + e.y ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dis[v] = dis[u] + e.y ;
        dep[v] = dep[u] + 1 ;
        dfs1(v,u) ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , pre[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    d[1] = 0 ; vis[1] = 1 ;
    for( int i = 2 ; i <= n ; i++ )
        pre[i] = 1 , d[i] = a[1][i] ;
    for( int k = 1 ; k < n ; k++ )
    {
        int x = 0 ;
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] < d[x] )
                x = i ;
        vis[x] = 1 ;
        G[x].push_back(pii(pre[x],a[x][pre[x]])) ;
        G[pre[x]].push_back(pii(x,a[x][pre[x]])) ;
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[x][i] )
                d[i] = a[x][i] , pre[i] = x ;
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int w , int pre )
{
    dep[u] = dep[pre] + 1 ;
    dis[u] = dis[pre] + w ;
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,e.y,u) ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-2*dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] >= a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int w , int pre )
{
    dep[u] = dep[pre] + 1 ;
    dis[u] = dis[pre] + w ;
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,e.y,u) ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-2*dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dep[v] = dep[u] + 1 ;
        dis[v] = dis[u] + e.y ;
        dfs1(v,u) ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-2*dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] >= a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    dep[u] = dep[pre]+1 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,u) ;
        dis[v] = dis[u] + e.y ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#include <bits/stdc++.h>
using namespace std ;
const int N = 2000 + 5 ;
const int inf = 0x3f3f3f3f ;
typedef pair<int,int> pii ;
#define x first
#define y second

int n , a[N][N] , d[N] , vis[N] ;

struct node
{
    int u , v , w ;
    bool operator < ( const node &rhs ) const
    {
        return d[u] > d[rhs.u] ;
    }
} ;
vector<pii> G[N] ;

void prim()
{
    memset(d,inf,sizeof(d)) ;
    priority_queue<node> Q ;
    Q.push((node){1,0,0}) ; d[1] = 0 ;
    while( Q.size() )
    {
        node tmp = Q.top() ; Q.pop() ;
        int u = tmp.u , v = tmp.v , w = tmp.w ;
        if( vis[u] ) continue ;
        vis[u] = 1 ;
        if( u && v )
        {
            G[u].push_back(pii(v,w)) ;
            G[v].push_back(pii(u,w)) ;
        }
        for( int i = 1 ; i <= n ; i++ )
            if( !vis[i] && d[i] > a[u][i] )
            {
                d[i] = a[u][i] ;
                Q.push((node){i,u,a[u][i]}) ;
            }
    }
}

int fa[N] , sz[N] , son[N] , top[N] , dep[N] ;
long long dis[N] ;

void dfs1( int u , int pre )
{
    fa[u] = pre ;
    sz[u] = 1 ;
    son[u] = 0 ;
    dep[u] = dep[pre]+1 ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v == pre ) continue ;
        dfs1(v,u) ;
        dis[v] = dis[u] + e.y ;
        if( !son[u] || sz[v] > sz[son[u]] )
            son[u] = v ;
        sz[u] += sz[v] ;
    }
}

void dfs2( int u , int tp )
{
    top[u] = tp ;
    if( son[u] ) dfs2(son[u],tp) ;
    for( auto e : G[u] )
    {
        int v = e.x ;
        if( v != fa[u] && v != son[u] ) dfs2(v,v) ;
    }
}

int lca( int u , int v )
{
    while( top[u] != top[v] )
    {
        if( dep[top[u]] < dep[top[v]] )
            swap(u,v) ;
        u = fa[top[u]] ;
    }
    return dep[u] < dep[v] ? u : v ;
}

int main()
{
    scanf( "%d" , &n ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= n ; j++ )
            scanf( "%d" , &a[i][j] ) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j <= i ; j++ )
            if( (i == j) == (a[i][j] != 0) || a[i][j] != a[j][i] )
                return puts("NO"),0 ;
    prim() ;
    dfs1(1,0) ;
    dfs2(1,1) ;
    for( int i = 1 ; i <= n ; i++ )
        for( int j = 1 ; j < i ; j++ )
            if( a[i][j] != dis[i]+dis[j]-dis[lca(i,j)] )
                return puts("NO"),0 ;
    return puts("YES"),0 ;
}


#define speed ios::sync_with_stdio(false)
#include<bits/stdc++.h>

#define ll long long
#define ld long double
#define mod 1000000007
#define nax 1000005
#define inf 100000000000000000LL
#define pb push_back
#define mp make_pair
#define in insert
#define ff first
#define ss second
#define pll pair<ll,ll>
#define vll vector<ll>
#define vb vector<bool>
#define sll set<ll>
#define mll map<ll,ll>
#define mis map<int,string>
#define all(n) n.begin(),n.end()
#define tr(container, it) for(__typeof(container.begin()) it = container.begin(); it != container.end(); it++)
#define lpl(i,a,b) for(ll i=a;i<=b;++i)
#define lplr(i,a,b) for(ll i=a;i>=b;--i)
#define lpv(c,it) for(vii::iterator it=(c).begin();it!=(c).end();it++)
#define test() int t; cin >> t; while(t--)

using namespace std;
const int N = 2e3+9;

ll arr[N], s[N], w[N][N], depth[N], parent[N][20], dist[N][20];
bool done[N][N], vis[N];
vector<pll > adj[N];

struct tree
{
	ll x,y,wt;
};
bool cmp(tree a,tree b)
{
	if(a.wt < b.wt)
		return true;
	return false;
}
void init()
{
	lpl(i,0,N-1)
	{
		s[i] = 1;
		arr[i] = i;
	}
}
ll root(ll i)
{
	while(arr[i] != i)
		i = arr[arr[i]];
	return i;
}

void dfs(ll curr,ll prev)
{
	vis[curr] = true;
	depth[curr] = depth[prev]+1;
	parent[curr][0] = prev;
	for(auto i: adj[curr])
	{
		if(!vis[i.ff])
		{
			dist[i.ff][0] = i.ss;
			dfs(i.ff, curr);
		}
	}
}
void fill_parent(ll n)
{
	lpl(i,1,19)
	{
		lpl(j,1,n)
		{
			dist[j][i] = dist[j][i-1]+dist[parent[j][i-1]][i-1];
			parent[j][i] = parent[parent[j][i-1]][i-1];
		}
	}
}
ll lca(ll x,ll y)
{
	if(depth[x] > depth[y])
		swap(x,y);
	ll diff = depth[y]-depth[x];
	ll ans=0; // weight of the path from x->y
	lpl(i,0,19)
	{
		if(diff&(1<<i))
		{
			ans += dist[y][i];
			y = parent[y][i];
		}
	}
	if(x == y)
		return ans;
	lplr(i,19,0)
	{
		if(parent[x][i] != parent[y][i])
		{
			ans += dist[x][i], ans += dist[y][i];
			x = parent[x][i], y = parent[y][i];
		}
	}
	ans += dist[x][0], ans += dist[y][0];
	return ans;
}

int main()
{
	speed;
	ll n;
	cin >> n;
	vector<tree> ar;
	tree obj;
	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			cin >> w[i][j];
			if(i!=j && w[i][j]==0)
			{
				cout << "NO";
				return 0;
			}
			obj.x=i, obj.y=j, obj.wt=w[i][j];
			ar.pb(obj);
		}
	}
	sort(all(ar), cmp);
	ll siz = ar.size();
	init();
	lpl(i,0,siz-1)
	{
		ll x = ar[i].x, y = ar[i].y, wt = ar[i].wt;
		ll root_x = root(x), root_y = root(y);
		if(root_x == root_y)
			continue;
		if(s[root_x] < s[root_y])
		{
			arr[root_x] = arr[root_y];
			s[root_y] += s[root_x];
		}
		else
		{
			arr[root_y] = arr[root_x];
			s[root_x] += s[root_y];
		}
		adj[x].pb({y,wt});
		adj[y].pb({x,wt});
	}
	/* MST ->
	lpl(i,1,n)
	{
		cout << i << " - > ";
		for(auto x: adj[i])
			cout << x.ff << " " << x.ss << endl;
	}*/
	dfs(1,0);

	fill_parent(n);

	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			ll z = lca(i,j);
			if(w[i][j] == z)
			{
				continue;
			}
			//cout <<i << " "<<j << " "<< z <<" " << w[i][j] << endl;
			cout << "NO" ;
			return 0;
		}
	}
	cout << "YES";
	return 0;
}


#define speed ios::sync_with_stdio(false)
#include<bits/stdc++.h>

#define ll long long
#define ld long double
#define mod 1000000007
#define nax 1000005
#define inf 100000000000000000LL
#define pb push_back
#define mp make_pair
#define in insert
#define ff first
#define ss second
#define pll pair<ll,ll>
#define vll vector<ll>
#define vb vector<bool>
#define sll set<ll>
#define mll map<ll,ll>
#define mis map<int,string>
#define all(n) n.begin(),n.end()
#define tr(container, it) for(__typeof(container.begin()) it = container.begin(); it != container.end(); it++)
#define lpl(i,a,b) for(ll i=a;i<=b;++i)
#define lplr(i,a,b) for(ll i=a;i>=b;--i)
#define lpv(c,it) for(vii::iterator it=(c).begin();it!=(c).end();it++)
#define test() int t; cin >> t; while(t--)

using namespace std;
const int N = 2e3+9;

ll arr[N], s[N], w[N][N], depth[N], parent[N][20], dist[N][20];
bool done[N][N], vis[N];
vector<pll > adj[N];

struct tree
{
	ll x,y,wt;
};
bool cmp(tree a,tree b)
{
	if(a.wt < b.wt)
		return true;
	return false;
}
void init()
{
	lpl(i,0,N-1)
	{
		s[i] = 1;
		arr[i] = i;
	}
}
ll root(ll i)
{
	while(arr[i] != i)
		i = arr[arr[i]];
	return i;
}

void dfs(ll curr,ll prev)
{
	vis[curr] = true;
	depth[curr] = depth[prev]+1;
	parent[curr][0] = prev;
	for(auto i: adj[curr])
	{
		if(!vis[i.ff])
		{
			dist[i.ff][0] = i.ss;
			dfs(i.ff, curr);
		}
	}
}
void fill_parent(ll n)
{
	lpl(i,1,19)
	{
		lpl(j,1,n)
		{
			dist[j][i] = dist[j][i-1]+dist[parent[j][i-1]][i-1];
			parent[j][i] = parent[parent[j-1][i-1]][i-1];
		}
	}
}
ll lca(ll x,ll y)
{
	if(depth[x] > depth[y])
		swap(x,y);
	ll diff = depth[y]-depth[x];
	ll ans=0; // weight of the path from x->y
	lpl(i,0,19)
	{
		if(diff&(1<<i))
		{
			ans += dist[y][i];
			y = parent[y][i];
		}
	}
	if(x == y)
		return ans;
	lplr(i,19,0)
	{
		if(parent[x][i] != parent[y][i])
		{
			ans += dist[x][i], ans += dist[y][i];
			x = parent[x][i], y = parent[y][i];
		}
	}
	ans += dist[x][0], ans += dist[y][0];
	return ans;
}

int main()
{
	speed;
	ll n;
	cin >> n;
	vector<tree> ar;
	tree obj;
	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			cin >> w[i][j];
			if(i!=j && w[i][j]==0)
			{
				cout << "NO";
				return 0;
			}
			obj.x=i, obj.y=j, obj.wt=w[i][j];
			ar.pb(obj);
		}
	}
	sort(all(ar), cmp);
	ll siz = ar.size();
	init();
	lpl(i,0,siz-1)
	{
		ll x = ar[i].x, y = ar[i].y, wt = ar[i].wt;
		ll root_x = root(x), root_y = root(y);
		if(root_x == root_y)
			continue;
		if(s[root_x] < s[root_y])
		{
			arr[root_x] = arr[root_y];
			s[root_y] += s[root_x];
		}
		else
		{
			arr[root_y] = arr[root_x];
			s[root_x] += s[root_y];
		}
		adj[x].pb({y,wt});
		adj[y].pb({x,wt});
	}
	dfs(1,0);
	fill_parent(n);

	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			ll z = lca(i,j);
			if(w[i][j] == z)
			{
				continue;
			}
			cout << "NO" ;
			return 0;
		}
	}
	cout << "YES";
	return 0;
}


#define speed ios::sync_with_stdio(false)
#include<bits/stdc++.h>

#define ll long long
#define ld long double
#define mod 1000000007
#define nax 1000005
#define inf 100000000000000000LL
#define pb push_back
#define mp make_pair
#define in insert
#define ff first
#define ss second
#define pll pair<ll,ll>
#define vll vector<ll>
#define vb vector<bool>
#define sll set<ll>
#define mll map<ll,ll>
#define mis map<int,string>
#define all(n) n.begin(),n.end()
#define tr(container, it) for(__typeof(container.begin()) it = container.begin(); it != container.end(); it++)
#define lpl(i,a,b) for(ll i=a;i<=b;++i)
#define lplr(i,a,b) for(ll i=a;i>=b;--i)
#define lpv(c,it) for(vii::iterator it=(c).begin();it!=(c).end();it++)
#define test() int t; cin >> t; while(t--)

using namespace std;
const int N = 2e3+9;

ll arr[N], s[N], w[N][N], depth[N], parent[N][16], dist[N][16];
bool done[N][N], vis[N];
vector<pll > adj[N];

struct tree
{
	ll x,y,wt;
};
bool cmp(tree a,tree b)
{
	if(a.wt < b.wt)
		return true;
	return false;
}
void init()
{
	lpl(i,0,N-1)
	{
		s[i] = 1;
		arr[i] = i;
	}
}
ll root(ll i)
{
	while(arr[i] != i)
		i = arr[arr[i]];
	return i;
}

void dfs(ll curr,ll prev)
{
	vis[curr] = true;
	depth[curr] = depth[prev]+1;
	parent[curr][0] = prev;
	for(auto i: adj[curr])
	{
		if(!vis[i.ff])
		{
			dist[i.ff][0] = i.ss;
			dfs(i.ff, curr);
		}
	}
}
void fill_parent(ll n)
{
	lpl(i,1,15)
	{
		lpl(j,1,n)
		{
			dist[j][i] = dist[j][i-1]+dist[parent[j][i-1]][i-1];
			parent[j][i] = parent[parent[j][i-1]][i-1];
		}
	}
}
ll lca(ll x,ll y)
{
	if(depth[x] > depth[y])
		swap(x,y);
	ll diff = depth[y]-depth[x];
	ll ans=0; // weight of the path from x->y
	lpl(i,0,15)
	{
		if(diff&(1<<i))
		{
			ans += dist[y][i];
			y = parent[y][i];
		}
	}
	if(x == y)
		return ans;
	lplr(i,15,0)
	{
		if(parent[x][i] != parent[y][i])
		{
			ans += dist[x][i], ans += dist[y][i];
			x = parent[x][i], y = parent[y][i];
		}
	}
	ans += dist[x][0], ans += dist[y][0];
	return ans;
}

int main()
{
	speed;
	ll n;
	cin >> n;
	vector<tree> ar;
	tree obj;
	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			cin >> w[i][j];
			if(i!=j && w[i][j]==0)
			{
				cout << "NO";
				return 0;
			}
			if(i==j && w[i][j]!=0)
			{
				cout << "NO";
				return 0;
			}
		}
	}
	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			if(w[i][j] != w[j][i])
			{
				cout << "NO";
				return 0;
			}
			if(i>j)
			{
				obj.x=i, obj.y=j, obj.wt=w[i][j];
				ar.pb(obj);
			}
		}
	}
	sort(all(ar), cmp);
	ll siz = ar.size();
	init();
	lpl(i,0,siz-1)
	{
		ll x = ar[i].x, y = ar[i].y, wt = ar[i].wt;
		ll root_x = root(x), root_y = root(y);
		if(root_x == root_y)
			continue;
		if(s[root_x] < s[root_y])
		{
			arr[root_x] = arr[root_y];
			s[root_y] += s[root_x];
		}
		else
		{
			arr[root_y] = arr[root_x];
			s[root_x] += s[root_y];
		}
		adj[x].pb({y,wt});
		adj[y].pb({x,wt});
		done[x][y] = done[y][x] = true;
	}
	/* MST ->
	lpl(i,1,n)
	{
		cout << i << " - > ";
		for(auto x: adj[i])
			cout << x.ff << " " << x.ss << endl;
	}*/
	dfs(1,0);

	fill_parent(n);

	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			if(done[i][j])
				continue;
			if(i==j)
				continue;
			ll z = lca(i,j);
			if(w[i][j] == z)
			{
				done[i][j] = done[j][i] = true;
				continue;
			}
			//cout <<i << " "<<j << " "<< z <<" " << w[i][j] << endl;
			cout << "NO" ;
			return 0;
		}
	}
	cout << "YES";
	return 0;
}


#define speed ios::sync_with_stdio(false)
#include<bits/stdc++.h>

#define ll long long
#define ld long double
#define mod 1000000007
#define nax 1000005
#define inf 100000000000000000LL
#define pb push_back
#define mp make_pair
#define in insert
#define ff first
#define ss second
#define pll pair<ll,ll>
#define vll vector<ll>
#define vb vector<bool>
#define sll set<ll>
#define mll map<ll,ll>
#define mis map<int,string>
#define all(n) n.begin(),n.end()
#define tr(container, it) for(__typeof(container.begin()) it = container.begin(); it != container.end(); it++)
#define lpl(i,a,b) for(ll i=a;i<=b;++i)
#define lplr(i,a,b) for(ll i=a;i>=b;--i)
#define lpv(c,it) for(vii::iterator it=(c).begin();it!=(c).end();it++)
#define test() int t; cin >> t; while(t--)

using namespace std;
const int N = 2e3+9;

ll arr[N], s[N], w[N][N], depth[N], parent[N][20], dist[N][20];
bool done[N][N], vis[N];
vector<pll > adj[N];

struct tree
{
	ll x,y,wt;
};
bool cmp(tree a,tree b)
{
	if(a.wt < b.wt)
		return true;
	return false;
}
void init()
{
	lpl(i,0,N-1)
	{
		s[i] = 1;
		arr[i] = i;
	}
}
ll root(ll i)
{
	while(arr[i] != i)
		i = arr[arr[i]];
	return i;
}

void dfs(ll curr,ll prev)
{
	vis[curr] = true;
	depth[curr] = depth[prev]+1;
	parent[curr][0] = prev;
	for(auto i: adj[curr])
	{
		if(!vis[i.ff])
		{
			dist[i.ff][0] = i.ss;
			dfs(i.ff, curr);
		}
	}
}
void fill_parent(ll n)
{
	lpl(i,1,19)
	{
		lpl(j,1,n)
		{
			dist[j][i] = dist[j][i-1]+dist[parent[j][i-1]][i-1];
			parent[j][i] = parent[parent[j-1][i-1]][i-1];
		}
	}
}
ll lca(ll x,ll y)
{
	if(depth[x] > depth[y])
		swap(x,y);
	ll diff = depth[y]-depth[x];
	ll ans=0; // weight of the path from x->y
	lpl(i,0,19)
	{
		if(diff&(1<<i))
		{
			ans += dist[y][i];
			y = parent[y][i];
		}
	}
	if(x == y)
		return ans;
	lplr(i,19,0)
	{
		if(parent[x][i] != parent[y][i])
		{
			ans += dist[x][i], ans += dist[y][i];
			x = parent[x][i], y = parent[y][i];
		}
	}
	ans += dist[x][0], ans += dist[y][0];
	return ans;
}

int main()
{
	speed;
	ll n;
	cin >> n;
	vector<tree> ar;
	tree obj;
	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			cin >> w[i][j];
			if(i!=j && w[i][j]==0)
			{
				cout << "NO";
				return 0;
			}
			obj.x=i, obj.y=j, obj.wt=w[i][j];
			ar.pb(obj);
		}
	}
	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			if(w[i][j] != w[j][i])
			{
				cout << "NO";
				return 0;
			}
		}
	}
	sort(all(ar), cmp);
	ll siz = ar.size();
	init();
	lpl(i,0,siz-1)
	{
		ll x = ar[i].x, y = ar[i].y, wt = ar[i].wt;
		ll root_x = root(x), root_y = root(y);
		if(root_x == root_y)
			continue;
		if(s[root_x] < s[root_y])
		{
			arr[root_x] = arr[root_y];
			s[root_y] += s[root_x];
		}
		else
		{
			arr[root_y] = arr[root_x];
			s[root_x] += s[root_y];
		}
		adj[x].pb({y,wt});
		adj[y].pb({x,wt});
	}
	dfs(1,0);
	fill_parent(n);

	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			ll z = lca(i,j);
			if(w[i][j] == z)
			{
				continue;
			}
			cout << "NO" ;
			return 0;
		}
	}
	cout << "YES";
	return 0;
}


#define speed ios::sync_with_stdio(false)
#include<bits/stdc++.h>

#define ll long long
#define ld long double
#define mod 1000000007
#define nax 1000005
#define inf 100000000000000000LL
#define pb push_back
#define mp make_pair
#define in insert
#define ff first
#define ss second
#define pll pair<ll,ll>
#define vll vector<ll>
#define vb vector<bool>
#define sll set<ll>
#define mll map<ll,ll>
#define mis map<int,string>
#define all(n) n.begin(),n.end()
#define tr(container, it) for(__typeof(container.begin()) it = container.begin(); it != container.end(); it++)
#define lpl(i,a,b) for(ll i=a;i<=b;++i)
#define lplr(i,a,b) for(ll i=a;i>=b;--i)
#define lpv(c,it) for(vii::iterator it=(c).begin();it!=(c).end();it++)
#define test() int t; cin >> t; while(t--)

using namespace std;
const int N = 2e3+3;

ll arr[N], s[N], w[N][N], depth[N], parent[N][16], dist[N][16];
bool done[N][N], vis[N];
vector<pll > adj[N];

struct tree
{
	ll x,y,wt;
};
bool cmp(tree a,tree b)
{
	if(a.wt < b.wt)
		return true;
	return false;
}
void init()
{
	lpl(i,0,N-1)
	{
		s[i] = 1;
		arr[i] = i;
	}
}
ll root(ll i)
{
	while(arr[i] != i)
		i = arr[arr[i]];
	return i;
}

void dfs(ll curr,ll prev)
{
	vis[curr] = true;
	depth[curr] = depth[prev]+1;
	parent[curr][0] = prev;
	for(auto i: adj[curr])
	{
		if(!vis[i.ff])
		{
			dist[i.ff][0] = i.ss;
			dfs(i.ff, curr);
		}
	}
}
void fill_parent(ll n)
{
	lpl(i,1,15)
	{
		lpl(j,1,n)
		{
			dist[j][i] = dist[j][i-1]+dist[parent[j][i-1]][i-1];
			parent[j][i] = parent[parent[j-1][i-1]][i-1];
		}
	}
}
ll lca(ll x,ll y)
{
	if(depth[x] > depth[y])
		swap(x,y);
	ll diff = depth[y]-depth[x];
	ll ans=0; // weight of the path from x->y
	lpl(i,0,15)
	{
		if(diff&(1<<i))
		{
			ans += dist[y][i];
			y = parent[y][i];
		}
	}
	if(x == y)
		return ans;
	lplr(i,15,0)
	{
		if(parent[x][i] != parent[y][i])
		{
			ans += dist[x][i], ans += dist[y][i];
			x = parent[x][i], y = parent[y][i];
		}
	}
	ans += dist[x][0], ans += dist[y][0];
	return ans;
}

int main()
{
	speed;
	ll n;
	cin >> n;
	vector<tree> ar;
	tree obj;
	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			cin >> w[i][j];
			if(i==j && w[i][j]!=0)
			{
				cout << "NO";
				return 0;
			}
			if(i!=j && w[i][j]==0)
			{
				cout << "NO";
				return 0;
			}
			obj.x=i, obj.y=j, obj.wt=w[i][j];
			ar.pb(obj);
		}
	}
	sort(all(ar), cmp);
	ll siz = ar.size();
	init();
	lpl(i,0,siz-1)
	{
		ll x = ar[i].x, y = ar[i].y, wt = ar[i].wt;
		ll root_x = root(x), root_y = root(y);
		if(root_x == root_y)
			continue;
		if(s[root_x] < s[root_y])
		{
			arr[root_x] = arr[root_y];
			s[root_y] += s[root_x];
		}
		else
		{
			arr[root_y] = arr[root_x];
			s[root_x] += s[root_y];
		}
		adj[x].pb({y,wt});
		adj[y].pb({x,wt});
		done[x][y] = true;
	}
	dfs(1,0);
	fill_parent(n);

	lpl(i,1,n)
	{
		lpl(j,1,n)
		{
			if(done[i][j])
				continue;
			ll z = lca(i,j);
			if(w[i][j] == z && w[j][i] == z)
			{
				done[i][j] = done[j][i] = true;
				continue;
			}
			cout << "NO" ;
			return 0;
		}
	}
	cout << "YES";
	return 0;
}