Problem:
Score : 500 points

Problem Statement

Given is a connected undirected graph with N vertices and M edges. The vertices are numbered 1 to N, and the edges are described by a grid of characters S.
If S_{i,j} is 1, there is an edge connecting Vertex i and j; otherwise, there is no such edge.

Determine whether it is possible to divide the vertices into non-empty sets V_1, \dots, V_k such that the following condition is satisfied. If the answer is yes, find the maximum possible number of sets, k, in such a division.

Every edge connects two vertices belonging to two "adjacent" sets. More formally, for every edge (i,j), there exists 1\leq t\leq k-1 such that i\in V_t,j\in V_{t+1} or i\in V_{t+1},j\in V_t holds.

Constraints

2 \leq N \leq 200

S_{i,j} is 0 or 1.

S_{i,i} is 0.

S_{i,j}=S_{j,i}

The given graph is connected.

N is an integer.

Input

Input is given from Standard Input in the following format:

N
S_{1,1}...S_{1,N}
:
S_{N,1}...S_{N,N}

Output

If it is impossible to divide the vertices into sets so that the condition is satisfied, print -1.
Otherwise, print the maximum possible number of sets, k, in a division that satisfies the condition.

Sample Input 1

2
01
10

Sample Output 1

2

We can put Vertex 1 in V_1 and Vertex 2 in V_2.

Sample Input 2

3
011
101
110

Sample Output 2

-1

Sample Input 3

6
010110
101001
010100
101000
100000
010000

Sample Output 3

4

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Wrong Answer)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Main main = new Main();
        main.solve();
    }
    public void solve() {
        Scanner scan = new Scanner(new BufferedReader(new InputStreamReader(System.in)));
        int N = scan.nextInt();
        int[][] edges = new int[N][N];
        for (int i = 0; i < N; i++) {
            String X = scan.next();
            char[] d = X.toCharArray();
            for (int j = 0; j < N; j++) {
                edges[i][j] = d[j] - '0';
            }
        }
        HashMap<Integer, Node> graph = new HashMap<>();
        PriorityQueue<Node> queue = new PriorityQueue<>(new NodeComparator());
        for (int i = 0; i < N; i++) {
            Node node = new Node();
            node.id = i;
            for (int j = 0; j < N; j++) {
                if (edges[i][j] == 0) {
                    continue;
                }
                node.add_neibor(j);
            }
            graph.put(i, node);
            queue.add(node);
        }
        Node node = queue.peek();
        int target = node.degree();
        int ans = -1;
        while (!queue.isEmpty()) {
            Node n = queue.poll();
            if (n.degree() != target) {
                break;
            }
            ans = Math.max(ans, check(edges, graph, n));
        }
        System.out.println(-1);
    }
    private int check(int[][] edges, HashMap<Integer, Node> graph, Node root) {
        for(Node x : graph.values()) {
            x.visited = false;
            x.distance = Integer.MAX_VALUE;
        }
        visit(graph, root);
        HashMap<Integer, List<Integer>> t = new HashMap<>();
        for (int x : graph.keySet()) {
            Node n = graph.get(x);
            if (!t.containsKey(n.distance)) {
                t.put(n.distance, new ArrayList());
            }
            t.get(n.distance).add(x);
        }
        for(int x : t.keySet()) {
            List<Integer> list = t.get(x);
            for (int i = 0; i < list.size(); i++) {
                int x_i = list.get(i);
                for (int j = 0; j < list.size(); j++) {
                    int x_j = list.get(j);
                    if (edges[x_i][x_j] != 0) {
                        return Integer.MAX_VALUE;
                    }
                }
            }
        }
        return t.size();
    }
    private void visit(HashMap<Integer, Node> graph, Node root) {
        Deque<Node> queue = new ArrayDeque<>();
        root.distance = 0;
        queue.add(root);
        while(!queue.isEmpty()) {
            Node current = queue.poll();
            if (current.visited) {
                continue;
            }
            current.visited = true;
            for(int x : current.neibors) {
                Node n = graph.get(x);
                n.distance = current.distance + 1;
                queue.add(n);
            }
        }
    }
    class NodeComparator implements Comparator<Node> {
        @Override
        public int compare(Node o1, Node o2) {
            int o1_d = o1.degree();
            int o2_d = o2.degree();
            if (o1_d != o2_d) {
                return Integer.compare(o1_d, o2_d);
            }
            return Integer.compare(o1.id, o2.id);
        }
    }
    class Node {
        boolean visited = false;
        int id = -1;
        int distance = Integer.MAX_VALUE;
        List<Integer> neibors = new ArrayList<>();
        void add_neibor(int x) {
            neibors.add(x);
        }
        int degree() {
            return neibors.size();
        }
    }
}