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 C++14 (Clang 3.8.0) (judge verdict: Accepted)

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstdlib>
#include<cassert>

#include<cmath>
#include<functional>
#include<algorithm>

#include<vector>
#include<string>
#include<queue>
#include<stack>
#include<set>
#include<unordered_set>
#include<map>
#include<unordered_map>
#include<bitset>
#include<tuple>

#define TEST {IS_TEST=true;}

using namespace std;
using ll = int_fast64_t;
using v_bool = vector <bool>;
using v_ll = vector <ll>;
using v_std = vector <string>;
using p_ll = pair <ll,ll>;
using vv_ll = vector <vector <ll> >;
using vp_ll = vector < p_ll >;

bool IS_TEST=false;
ll ll_min=1LL<<63;
ll ll_max=~ll_min;
ll MOD = 1000000007;


template<class T> bool show_nl(const T&){ return true;}
bool show_nl(const ll&){ return false;}
template<class T,class S> bool show_nl(const pair<T,S>&){ return false;}

template<class T> void show(const T& x,bool newline=false){
  if (!IS_TEST) return;
  cout << x; if (newline) cout << " <#>" <<  endl;
}
void show(const string& x,bool newline=true){
  if (!IS_TEST) return;
  cout << x; if (newline) cout << endl;
}
template<class T,class S> void show(const pair<T,S>& x,bool newline=false){
  if (!IS_TEST) return;
  cout << "{ " << x.first << " " << x.second << " }";
  if (newline) cout << " <#>" <<  endl;
}
template<class T> void show_common3(const T&x){
  if (!IS_TEST) return;
  auto itr=x.begin();
  if (x.begin()==x.end()) {cout<<"<NULL>"<<endl;return;}
  if (show_nl(*itr)){
    cout << "--------------------------------" << endl;
    auto itr=x.begin();
    while(itr!=x.end()){ show(*itr); itr++;}
    cout << "--------------------------------" << endl;
  }else{
    if (itr==x.end()){ cout<<endl; return;}
    while(true){
      show(*itr);itr++;
      if (itr==x.end()) break; else cout << " ";
    }
    cout << endl;
  }
}
template<class T> void show(const vector<T>& x,bool newline=false){
  if (!IS_TEST) return; show_common3(x);
}
template<class T,class S> void show(const set<T,S>& x,bool newline=false){
  if (!IS_TEST) return; show_common3(x);
}
template<class T,class S> void show(const multiset<T,S>& x,bool newline=false){
  if (!IS_TEST) return; show_common3(x);
}
template<class T> void show(const unordered_set<T>& x,bool newline=false){
  if (!IS_TEST) return; show_common3(x);
}
template<class T,class S,class U> void show(const map<T,S,U>& x,bool newline=false){
  if (!IS_TEST) return; show_common3(x);
}
template<class T,class S,class U> void show(const multimap<T,S,U>& x,bool newline=false){
  if (!IS_TEST) return; show_common3(x);
}
template<class T,class S> void show(const unordered_map<T,S>& x,bool newline=false){
  if (!IS_TEST) return; show_common3(x);
}

void load(ll& x){ cin >> x;}
void load(string& x){ cin >> x;}
void load(v_ll& v,ll b,ll e){
    v.assign(e+1,0);
    for(ll i=b;i<e;i++)cin >> v[i];
}
v_ll loadvec0(ll n){
    v_ll v(n+1,0);
    for(ll i=0;i<n;i++)cin >> v[i];
    return v;
}
v_ll loadvec1(ll n){
    v_ll v(n+2,0);
    for(ll i=1;i<=n;i++)cin >> v[i];
    return v;
}

void disp(const ll& x){ cout << x << endl;}
void disp(const string& x){ cout << x << endl;}
void disp(const v_ll& v,ll b,ll e){
    for(ll i=b;i<e;i++){
        if (i!=b) cout << " ";
        cout << v[i];
    }
    cout << endl;
}

v_ll arange(ll n){
    v_ll v(n+1,0);
    for(ll i=0;i<=n;i++)v[i]=i;
    return v;
}

ll vec_sum(const v_ll& v,ll b,ll e){
    ll ans=0;
    for(ll i=b;i<e;i++)ans+=v[i];
    return ans;
}


template<class T> void refl_max(T& x,const T& y){ if (x>=y) return; x=y; }
template<class T> void refl_min(T& x,const T& y){ if (x<=y) return; x=y; }

template<class T,class S> void refl_max(T& x,const T& y,S& xx,const S& yy){
  if (x>=y) return; x=y; xx=yy;
}
template<class T,class S> void refl_min(T& x,const T& y,S& xx,const S& yy){
  if (x<=y) return; x=y; xx=yy;
}


class Neighbor{
    public:
    bool dir;
    ll from,to,edge;
    Neighbor(ll w,ll x,ll y,bool z){from=w;to=x;edge=y;dir=z;}
    inline constexpr operator ll()const{ return to;} 
};
class Node{
    public:
    vector<Neighbor> neighbor;
    bool valid; ll idx;
    Node(bool v,ll i){valid=v;idx=i;}
    inline constexpr Neighbor& operator[](ll n){ return neighbor[n];}
    inline vector<Neighbor>::iterator begin(){ return neighbor.begin();}
    inline vector<Neighbor>::iterator end(){ return neighbor.end();}
    inline constexpr void push_back(ll w,ll x,ll y, bool z){neighbor.push_back(Neighbor(w,x,y,z));}
    inline constexpr ll size(){return neighbor.size();}
    /*----------------*/
};
class Edge{
    public:
    bool valid;  bool indir;
    ll n1,n2; ll idx;
    Edge(bool v,ll i,ll x,ll y,bool z){valid=v;idx=i;n1=x;n2=y;indir=z;}
    /*----------------*/

};
class Graph{
    public:
    vector<Node> n;
    vector<Edge> e;
    void init(ll nodes, ll idx_node, ll idx_edge){
        n.clear(); e.clear();
        for (ll i=0;i<idx_node;i++) n.push_back(Node(false,n.size()));
        for (ll i=0;i<idx_edge;i++) e.push_back(Edge(false,e.size(),-1,-1,true));
        for (ll i=0;i<nodes;i++) n.push_back(Node(true,n.size()));
    }
    ll edge(ll f, ll t, bool indir=true){
        assert(f>=0&&f<n.size()&&t>=0&&t<n.size());
        ll i=e.size();e.push_back(Edge(true,i,f,t,!indir));
        n[f].push_back(f,t,i,true);
        n[t].push_back(t,f,i,indir);
        return i;
    }
    ll d_edge(ll f, ll t){return edge(f,t,false);}
    inline constexpr Node& operator[](ll x){ return n[x];} 

    void show(){
        for (ll i=0;i<n.size();i++){
            if(!n[i].valid)continue;
            cout << i << "\t";
            for(ll j=0;j<n[i].size();j++){
                if (n[i][j].dir) cout << n[i][j].to << " ";
            }
            cout << endl;
        }
    }
    /*----------------*/
};


ll N;
vector<string> M;
int main(){
  cin >> N;
  Graph G;
  for (ll i=0;i<N;i++){
    string s; cin >> s;
    M.push_back(s);
  }
  G.init(N,0,0);
  for (ll i=0;i<N;i++){
    for (ll j=i+1;j<N;j++){
      if (M[i][j]=='1'){
        G.edge(i,j);
      }
    }
  }
  ll mostmostfar=0;
  for (ll s=0;s<N;s++){
    queue<ll> que;
    que.push(s);
    v_bool arv(N,false);
    v_bool pushed(N,false);
    v_ll dist(N,0);
    ll mostfar=0;
    while (!que.empty()){
      ll f=que.front(); que.pop();
      arv[f]=true;
      mostfar=dist[f];
      for(ll i=0;i<G[f].size();i++){
        ll t=G[f][i];
        if (arv[t])continue;
        if (pushed[t])continue;
        que.push(t);
        pushed[t]=true;
        dist[t]=dist[f]+1;
      }
    }
    for (ll i=0;i<G.e.size();i++){
      if (abs(dist[G.e[i].n1]-dist[G.e[i].n2])!=1){
        cout << -1 << endl;
        return 0;
      }
    }
    refl_max(mostmostfar,mostfar);
  }
  cout << mostmostfar+1 << endl;
}