#include <algorithm>
#include <bitset>
#include <cassert>
#include <chrono>
#include <complex>
#include <cstring>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>

using namespace std;


class union_find
{
    struct node
    {
        node *link = nullptr;
        bool color = 0;
        bool diff_root = false;
        size_t cnt[2] = {1, 0};
        size_t size() const { return cnt[0] + cnt[1]; }
    };

    const size_t n;
    node *const tree;

    node *find(node *const ptr)
    {
        if(!ptr->link) return ptr;
        node *const root = find(ptr->link);
        if(ptr->link->diff_root) ptr->diff_root ^= 1;
        return ptr->link = root;
    }

    bool color(node *const ptr)
    {
        node *const root = find(ptr);
        return ptr->diff_root != root->color;
    }

    bool unite(node *x, node *y, bool diff_color)
    {
        diff_color ^= color(x) != color(y);
        x = find(x), y = find(y);
        if(x == y) return !diff_color;
        if(x->size() > y->size()) std::swap(x, y);
        y->link = x;
        if(diff_color)
        {
            y->color ^= 1;
            std::swap(y->cnt[0], y->cnt[1]);
        }
        y->diff_root = x->color != y->color;
        return true;
    }

public:
    explicit union_find(size_t _n) : n(_n), tree(new node[n]) {}

    size_t find(const size_t x)
    {
        assert(x < n);
        return find(tree + x) - tree;
    }

    size_t size() const { return n; }

    size_t size(const size_t x)
    {
        assert(x < n);
        return find(tree + x)->size();
    }

    bool color(const size_t x)
    {
        assert(x < n);
        return color(tree + x);
    }

    bool same(const size_t x, const size_t y)
    {
        assert(x < n && y < n);
        return find(tree + x) == find(tree + y);
    }

    // return if the condition given is possible.
    bool unite(const size_t x, const size_t y, const bool diff_color = true)
    {
        assert(x < n && y < n);
        return unite(tree + x, tree + y, diff_color);
    }
}; // class union_find


int main(int argc, char *argv[])
{
    std::ios::sync_with_stdio(false), std::cin.tie(nullptr);

    int n;
    cin >> n;
    vector<string> g(n);
    for(auto &s:g) cin>>s;

    int dist[222][222];
    for(int i=0; i<n; ++i)
        for(int j=0; j<n; ++j)
            dist[i][j]=n;

    union_find uf(n);
    for(int i = 0; i < n; ++i)
    {
        for(int j = 0; j < n; ++j)
        {
            if(g[i][j] - '0')
            {
                if(!uf.unite(i,j))
                {
                    cout << -1 << "\n";
                    return 0;
                }
                dist[i][j] = 1;
            }
            else
            {
                if(i==j)
                {
                    dist[i][j]=0;
                }
            }
        }
    }
    for(int k = 0; k < n; ++k)
    {
        for(int i = 0; i < n; ++i)
        {
            for(int j = 0; j < n; ++j)
            {
                dist[i][j]=min(dist[i][j], dist[i][k] + dist[k][j]);
            }
        }
    }

    int ans=0;
    for(int i = 0; i < n; ++i)
    {
        vector<int> comp;
        for(int j = 0; j < n; ++j)
        {
            if(uf.find(j)==i)
            {
                comp.emplace_back(j);
            }
        }
        int k=0;
        for(int a : comp)
        {
            for(int b : comp)
            {
                if(k<=dist[a][b])
                {
                    k=dist[a][b]+1;
                }
            }
        }
        ans+=k;
    }
    cout << ans << "\n";
}


Measured memory_bytes: 512