#include <iostream>
#include <fstream>
#include <string>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <utility>
#include <numeric>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <unordered_map>
#include <limits.h>
#include <bitset>
#include <math.h>
#define int long long
using namespace std;
using P = pair<int, int>;
using ll = long long;
using prique = priority_queue<int>;
const int MOD = 1000000007;
const int INF = LLONG_MAX/3;
const int MAX = 510000;

/*-----Library-----*/

struct UnionFind {
    vector<int> par; // 親ノード
    vector<int> rank; // ランク
    vector<int> sizeuf; //要素数
    UnionFind(int n = 1) {
        init(n);
    }
    
    void init(int n = 1) {
        par.resize(n); rank.resize(n); sizeuf.resize(n);
        for (int i = 0; i < n; ++i) {
            par[i] = i;
            rank[i] = 0;
            sizeuf[i]=1;
        }
    }
    
    int root(int x) {
        if (par[x] == x) {
            return x;
        }
        else {
            int r = root(par[x]);
            return par[x] = r;
        }
    }
    
    bool issame(int x, int y) {
        return root(x) == root(y);
    }
    
    bool merge(int x, int y) {
        x = root(x); y = root(y);
        if (x == y) return false;
        if (rank[x] < rank[y]) swap(x, y);
        if (rank[x] == rank[y]) ++rank[x];
        par[y] = x;
        sizeuf[x]+=sizeuf[y];
        return true;
    }
    
    int size(int x){
        return sizeuf[root(x)];
    }
};

long long gcd(long long a,long long b){
    if(b==0)return a;
    return gcd(b,a%b);
}

long long lcm(long long i,long long j){
    return i*(j/gcd(i,j));
}

long long fac[MAX], finv[MAX], inv[MAX];
// テーブルを作る前処理
void COMinit() {
    fac[0] = fac[1] = 1;
    finv[0] = finv[1] = 1;
    inv[1] = 1;
    for (int i = 2; i < MAX; i++){
        fac[i] = fac[i - 1] * i % MOD;
        inv[i] = MOD - inv[MOD%i] * (MOD / i) % MOD;
        finv[i] = finv[i - 1] * inv[i] % MOD;
    }
}

// 二項係数計算
long long COM(int n, int k){
    if (n < k) return 0;
    if (n < 0 || k < 0) return 0;
    return fac[n] * (finv[k] * finv[n - k] % MOD) % MOD;
}

/*-----Library-----*/

struct edge{
    int to;
    int cost;
};

vector<edge> es[310];
int d[310];
int n;

void dijkstra(int s){
    for(int i=0;i<n;i++){
        d[i]=INF;
    }
    d[s]=0;
    priority_queue<P,vector<P>,greater<P>> task;
    task.push(P(0,s));
    for(int i=0;i<es[s].size();i++)task.push(P(es[s][i].cost,es[s][i].to));
    while(!task.empty()){
        P p=task.top();
        task.pop();
        int v=p.second;
        if(d[v]<p.first)continue;
        for(int i=0;i<es[v].size();i++){
            edge e=es[v][i];
            if(d[e.to]>d[v]+e.cost){
                d[e.to]=d[v]+e.cost;
                task.push((P(d[e.to],e.to)));
            }
        }
    }
}
signed main(){
    cin>>n;
    int dis[310][310];
    vector<pair<int,P>> div;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            cin>>dis[i][j];
            if(i<j)div.push_back(make_pair(dis[i][j],P(i,j)));
        }
    }
    sort(div.begin(),div.end());
    int m=n*(n-1)/2;
    int ans=0;
    for(int i=0;i<m;i++){
        int f=div[i].second.first;
        int t=div[i].second.second;
        dijkstra(f);
        if(d[t]<div[i].first){
            cout<<-1<<endl;
            return 0;
        }else if(d[t]>div[i].first){
            es[f].push_back({t,div[i].first});
            es[t].push_back({f,div[i].first});
            ans+=div[i].first;
        }
    }
    cout<<ans<<endl;
    return 0;
}



Measured memory_bytes: 2296