#include <bits/stdc++.h>

using namespace std;

template <typename T>
map<T, int> reduction(vector<T> values) {
    sort(values.begin(), values.end());
    values.resize(unique(values.begin(), values.end()) - values.begin());
    map<T, int> reduction_mapping;
    for (int i = 0; i < (int) values.size(); ++i) {
        reduction_mapping[values[i]] = i;
    }
    return reduction_mapping;
}

template <typename N, typename W>
struct Edge {
    N u, v;
    W weight;
    int simple_u, simple_v;
    Edge(N u, N v, W weight): u(u), v(v), weight(weight) {}
    Edge reverse() {
        return Edge(v, u, weight);
    }
};

template <typename N, typename W>
struct Graph {
    int n;
    vector<vector<Edge<N, W>>> adj_list;
    map<N, int> node_to_id;
    Graph(vector<Edge<N, W>>& edges) {
        vector<N> all_nodes;
        for (auto& edge : edges) {
            all_nodes.push_back(edge.u);
            all_nodes.push_back(edge.v);
        }
        node_to_id = reduction(all_nodes);
        n = (int) node_to_id.size();
        adj_list = vector<vector<Edge<N, W>>>(n);
        for (auto& edge : edges) {
            edge.simple_u = node_to_id[edge.u];
            edge.simple_v = node_to_id[edge.v];
            adj_list[edge.simple_u].push_back(edge);
        }
    }
    vector<W> _dijkstra(int start_id) {
        priority_queue<pair<W, int>, vector<pair<W, int>>, greater<pair<W, int>>> pq;
        pq.push(make_pair(0, start_id));
        vector<bool> visited(n, false);
        vector<W> dist(n, numeric_limits<W>::max());
        while (!pq.empty()) {
            auto p = pq.top();
            W current_dist = p.first;
            int node_id = p.second;
            pq.pop();
            if (visited[node_id]) {
                continue;
            }
            dist[node_id] = current_dist;
            visited[node_id] = true;
            for (auto& edge : adj_list[node_id]) {
                pq.push(make_pair(edge.weight + current_dist, edge.v));
            }
        }
        return dist;
    }
    vector<W> dijkstra(N start_node) {
        return _dijkstra(node_to_id[start_node]);
    }
    W diameter() {
        W diam = 0;
        for (int i = 0; i < n; ++i) {
            vector<W> dists = _dijkstra(i);
            diam = max(diam, *max_element(dists.begin(), dists.end()));
        }
        return diam;
    }
    vector<int> get_bipartition() {
        vector<int> colors(n, -1);
        function<bool (int, int)> color = [&](int i, int c) {
            if (colors[i] != -1) {
                return colors[i] == c;
            }
            colors[i] = c;
            for (auto& edge : adj_list[i]) {
                if (!color(edge.v, 1-c)) {
                    return false;
                }
            }
            return true;
        };
        for (int i = 0; i < n; ++i) {
            if (colors[i] == -1 && !color(i, 0)) {
                return vector<int>();
            }
        }
        return colors;
    }
    bool is_bipartite() {
        return get_bipartition().size() != 0;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int n;
    cin >> n;
    vector<Edge<int, int>> edges;
    for (int i = 0; i < n; ++i) {
        string s;
        cin >> s;
        for (int j = 0; j < n; ++j) {
            if (s[j] == '1') {
                edges.push_back(Edge<int, int>(i, j, 1));
            }
        }
    }
    Graph<int, int> graph(edges);
    if (!graph.is_bipartite()) {
        cout << -1 << endl;
    } else {
        cout << graph.diameter()+1 << endl;
    }
    return 0;
}


Measured memory_bytes: 2420