#include <bits/stdc++.h>

#define M_PI       3.14159265358979323846   // pi

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<ll> VI;
typedef pair<ll, ll> P;
typedef tuple<ll, ll, ll> t3;
typedef tuple<ll, ll, ll, ll> t4;
typedef tuple<ll, ll, ll, ll, ll> t5;

#define rep(a,n) for(ll a = 0;a < n;a++)
#define repi(a,b,n) for(ll a = b;a < n;a++)

using namespace std;

static const ll INF = 1e15;

template<typename T>
static inline void chmin(T & ref, const T  value) {
    if (ref > value) ref = value;
}

template<typename T>
static inline void chmax(T & ref, const T value) {
    if (ref < value) ref = value;
}

struct warshall_floyd {
    static void solve(vector<vector<ll>>& d) {
        int n = d.size();
        rep(k, n) {
            rep(i, n) {
                rep(j, n) {
                    d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
                }
            }
        }
    }
};


struct edge {
    int from;
    int to;
    ll cost;
    edge(){}
    edge(int a, int b, ll c) : from(a), to(b), cost(c){}
};

struct UnionFind {
public:
    vector <ll> par; // 
    vector <ll> siz; // 

    UnionFind(ll sz_) : par(sz_), siz(sz_, 1LL) {
        for (ll i = 0; i < sz_; ++i) par[i] = i;
    }
    void init(ll sz_) {
        par.resize(sz_);
        siz.assign(sz_, 1LL);
        for (ll i = 0; i < sz_; ++i) par[i] = i;
    }

    ll root(ll x) {
        while (par[x] != x) {
            x = par[x] = par[par[x]];
        }
        return x;
    }

    bool merge(ll x, ll y) {
        x = root(x);
        y = root(y);
        if (x == y) return false;
        if (siz[x] < siz[y]) swap(x, y);
        siz[x] += siz[y];
        par[y] = x;
        return true;
    }

    bool issame(ll x, ll y) {
        return root(x) == root(y);
    }

    ll size(ll x) {
        return siz[root(x)];
    }
};

struct KruskalRunner {
    //コストの取り方で最大全域木も計算可能
    static bool orderByCost(const edge& e1, const edge& e2) {
        return e1.cost < e2.cost;
    }

    ll solve(int vCount, vector<edge>& edges) {
        sort(edges.begin(), edges.end(), orderByCost);
        UnionFind uf = UnionFind(vCount);
        ll sum = 0;
        for (int i = 0; i < edges.size(); ++i) {
            edge e = edges[i];
            if (!uf.issame(e.from, e.to)) {
                uf.merge(e.from, e.to);
                sum += e.cost;
            }
        }
        return sum;
    }
};
int main() {
    ll n;
    cin >> n;
    vector<vector<ll>> graph(n, vector<ll>(n, INF));
    rep(i, n) {
        rep(j, n) {
            ll c;
            cin >> c;
            graph[i][j] = c;
        }
    }
    if (n == 1) {
        cout << 0 << endl;
        return 0;
    }
    vector<vector<ll>> source = graph;
    warshall_floyd::solve(graph);
    rep(i, n) {
        rep(j, n) {
            if (source[i][j] != graph[i][j]) {
                cout << -1 << endl;
                return 0;
            }
        }
    }
    ll sum = 0;
    rep(i, n) {
        rep(j, i) {
            ll lower = INF;
            rep(k, n) {
                if (i == k || j == k) continue;
                chmin(lower, graph[i][k] + graph[j][k]);
            }
            if (lower > graph[i][j]) {
                sum += graph[i][j];
            }
        }
    }
    cout << sum << endl;
    return 0;
}



Measured memory_bytes: 5044