#include <stdio.h>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <vector>
#include <string>
#include <bitset>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <utility>
#include <numeric>
#include <complex>
#include <sstream>
#include <fstream>
#include <iomanip>
#include <cassert>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <functional>
using namespace std;
typedef long long ll;
const double EPS = 1e-9;
typedef vector<int> vint;
typedef vector<vector<int>> v2int;
typedef vector<ll> vll;
typedef vector<vector<ll>> v2ll;
typedef list<int> liint;
typedef pair<int, int> pint;
const int INF = int(2e9);
const ll LINF = ll(2e9) * ll(2e9);
#define rep(i, n) REP(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define MSG(a) cout << #a << " " << a << endl;
#define REP(i, x, n) for(int i = x; i < n; i++)
template<class T, class C> void chmax(T& a, C b) { a > b ? : a = b; }
template<class T, class C> void chmin(T& a, C b) { a < b ? : a = b; }

class warshall_floyd
{
private:
    int node_num;
    bool is_negative_graph;
    std::vector<std::vector<long long>> cost_matrix;//隣接行列を構築
    std::vector<std::vector<int>> pred;//経路（遷移元）を保持

public:
    warshall_floyd(const int node_num, const std::vector<std::vector<long long>> &adj_matrix);
    long long get_cost(int start, int end) const;
};

warshall_floyd::warshall_floyd(const int node_num,
    const std::vector<std::vector<long long>> &adj_matrix) :
    cost_matrix(adj_matrix),
    node_num(node_num),
    is_negative_graph(false),
    pred(node_num + 1, std::vector<int>(node_num + 1, INF))
{
    //predの初期化
    for (int i = 0; i <= node_num; i++) {
        for (int j = 0; j <= node_num; j++) {
            if (i == j) pred[i][j] = -1;
            else if (adj_matrix[i][j] < LINF) {
                pred[i][j] = i;
            }
        }
    }
    //ワーシャルフロイドの更新式
    for (int k = 0; k <= node_num; k++) {
        for (int i = 0; i <= node_num; i++) {
            for (int j = 0; j <= node_num; j++) {
                if (cost_matrix[i][k] < LINF && cost_matrix[k][j] < LINF) {
                    if (cost_matrix[i][k] + cost_matrix[k][j] < cost_matrix[i][j]) {
                        cost_matrix[i][j] = cost_matrix[i][k] + cost_matrix[k][j];
                        //経路復元用
                        //pred[i][j]にはi→jの最短経路におけるjの1つ前の頂点が入る。
                        //pred[k][j]にはk→jの最短経路におけるjの1つ前の頂点が入っている。
                        //この処理を通るということは最短経路がkを使った経路に変わる
                        //ということでありi→jへの経路の中にk→jの最短経路を含むことになる。
                        //従って新しいi→jにおけるjの１つ前の頂点は
                        //k→jにおけるjの１つ前の頂点、すなわちpred[k][j]となる。
                        pred[i][j] = pred[k][j];
                    }
                }
            }
        }
    }

}



long long warshall_floyd::get_cost(int start, int end) const {
    return cost_matrix[start][end];
}

int dfs(unordered_map<int, unordered_set<int>>& graph, int t, int now, int pre, int depth, set<int>& visited) {
    if (now == t) return depth;
    int ans = INF;
    
    for (auto &adj : graph[now]) {
        if (adj == pre) continue;
        if (visited.find(adj) != visited.end()) continue;
        visited.insert(adj);
        ans = min(ans, dfs(graph, t, adj, now, depth + 1, visited));
        visited.erase(adj);
    }
    return ans;
}

int calc_dist(unordered_map<int, unordered_set<int>>& graph, int s, int t) {
    set<int> visited;
    return dfs(graph, t, s, -1, 0, visited);
}
bool is_bipartite_graph(vector<string>& S) {
    int nd = 0;
    deque<int> que;
    que.push_back(nd);
    vint colored(S.size(), 0);

    char now_color = 'B';
    colored[nd] = now_color;
    while (1) {
        if (que.size() <= 0) break;
        nd = que.front();
        que.pop_front();
        
        rep(i, S[nd].size()){
            if (S[nd][i] == '0') continue;
            if (colored[i] != 0) {
                if (colored[nd] == colored[i]) {
                    return false;
                }
            }
            else {
                if (colored[nd] == 'B') colored[i] = 'W';
                else colored[i] = 'B';
                que.push_back(i);
            }

        }

    }
    return true;
}

int main() {
    int N;
    cin >> N;
    vector<string> S(N);
    int edge_num = 0;
    v2ll graph(N + 1, vll(N + 1, LINF));
    rep(i, N) {
        cin >> S[i];
        rep(j, N) {
            if (S[i][j] == '1') {
                edge_num++;
                graph[i][j] = 1;
                graph[j][i] = 1;
            }

        }
    }
    warshall_floyd wf(N, graph);

    if (is_bipartite_graph(S) == false) {
        cout << -1 << endl;
        return 0;
    }

    
    //edge_num /= 2;
    //set<int> group1, group2;
  /*  rep(i, N) {
        if (group2.find(i) == group2.end()) {
            group1.insert(i);
            rep(j, N) {
                if (S[i][j] == '1') {
                    group2.insert(j);
                }
            }
        }
        else {
            rep(j, N) {
                if (S[i][j] == '1') {
                    if (group2.find(j) != group2.end()) {
                        cout << -1 << endl;
                        return 0;
                    }
                    else {
                        group1.insert(j);
                    }
                }
            }
        }
        
    }*/
    ll ans = 0;
    rep(i, N) {
        REP(j, i + 1, N)
            ans = max(ans, wf.get_cost(i, j));
    }
    
    cout << ans + 1 << endl;
    return 0;
}

Measured memory_bytes: 1152