/*やったぜ。　投稿者：変態糞土方 (8月16日（水）07時14分22秒)

昨日の8月15日にいつもの浮浪者のおっさん（60歳）と先日メールくれた汚れ好きの土方のにいちゃん

（45歳）とわし（53歳）の3人で県北にある川の土手の下で盛りあったぜ。

今日は明日が休みなんでコンビニで酒とつまみを買ってから滅多に人が来ない所なんで、

そこでしこたま酒を飲んでからやりはじめたんや。

3人でちんぽ舐めあいながら地下足袋だけになり持って来たいちぢく浣腸を3本ずつ入れあった。

しばらくしたら、けつの穴がひくひくして来るし、糞が出口を求めて腹の中でぐるぐるしている。

浮浪者のおっさんにけつの穴をなめさせながら、兄ちゃんのけつの穴を舐めてたら、

先に兄ちゃんがわしの口に糞をドバーっと出して来た。

それと同時におっさんもわしも糞を出したんや。もう顔中、糞まみれや、

3人で出した糞を手で掬いながらお互いの体にぬりあったり、

糞まみれのちんぽを舐めあって小便で浣腸したりした。ああ～～たまらねえぜ。

しばらくやりまくってから又浣腸をしあうともう気が狂う程気持ちええんじゃ。

浮浪者のおっさんのけつの穴にわしのちんぽを突うずるっ込んでやると

けつの穴が糞と小便でずるずるして気持ちが良い。

にいちゃんもおっさんの口にちんぽ突っ込んで腰をつかって居る。

糞まみれのおっさんのちんぽを掻きながら、思い切り射精したんや。

それからは、もうめちゃくちゃにおっさんと兄ちゃんの糞ちんぽを舐めあい、

糞を塗りあい、二回も男汁を出した。もう一度やりたいぜ。

やはり大勢で糞まみれになると最高やで。こんな、変態親父と糞あそびしないか。

ああ～～早く糞まみれになろうぜ。

岡山の県北であえる奴なら最高や。わしは163*90*53,おっさんは165*75*60、や

糞まみれでやりたいやつ、至急、メールくれや。

土方姿のまま浣腸して、糞だらけでやろうや。*/
#include "bits/stdc++.h"
#include <numeric>
#define rep(i,n) for(int i = 0; i < n; i++)
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
#define llMAX numeric_limits<long long>::max()
#define intMAX numeric_limits<int>::max()
#define llMIN numeric_limits<long long>::min()
#define intMIN numeric_limits<int>::min()
#define d_5 100000
#define d9_7 1000000007
#define vll vector<vector<long long>>
#define vl vector<long long>
#define vi vector<int>
#define vii vector<vector<int>>
#define pb push_back
#define pf push_front
#define ld long double
//木構造グラフ
struct edge{
  int to;
  ll length;
  int num;
  int pair;
};
struct treev{
  int num;
  vector<int> nexts;
};
vector<treev> vs;
vector<edge> es;

int cmax=0;
void createtreenode(int num){//引数は頂点の数
  vs=vector<treev>(num);
  /*treev* newt;
  try{
      treev* newt=new treev;
  }
  catch (std::bad_alloc&) {
      // メモリ確保に失敗
      // エラー処理
  }*/
  rep(i,num){
    vs[i].num=i;
  }
  return ;
}
void insertree(ll len,int Va,int Vb,int num){//結ぶ頂点を
  es.pb({Va,len,num,-1});
  es.pb({Vb,len,num,-1});
  int size=es.size();
  es[size-1].pair=size-2;
  es[size-2].pair=size-1;
  vs[Va].nexts.push_back(size-1);
  vs[Vb].nexts.push_back(size-2);
  
  return;
}
void DFS(int root,ll depth,int pre, int precol){
  //ここにやりたい処理を書く
  int ncnt=0;
  for(auto i:vs[root].nexts){
    if(pre==es[i].to){
      continue;
    }
    
    DFS(es[i].to,depth+es[i].length,root,ncnt);
  }
  return;
}
struct operatedata{
  int num;
  int prenum;
  ll depth;
};
deque<operatedata> opera;
vi past;
int tmpdepthmax=0;
int ngflag;
void BFS(int ini){
  opera.clear();
  opera.pb({ini,-1,0});
  int pre=-1;
  while(opera.size()!=0 &&ngflag==0){
    int root=opera.front().num;
    int pre=opera.front().prenum;
    ll depth=opera.front().depth;
    opera.pop_front();
    //cout<<"e "<<root<<" depth "<<depth<<" pre "<<pre<<endl;
    if(past[root]!=-10 && pre!=-1){
      if(abs(past[pre]-past[root])==1){
        //cout<<"cnti "<<past[pre]<<" "<<past[root]<<endl;
        continue;

      }else{
        ngflag=1;
        //cout<<"flaged"<<endl;
        break;
      }
    }
    tmpdepthmax=max(tmpdepthmax,(int)depth);
    past[root]=depth;
    //ここにやりたい処理を書く
    for(int i:vs[root].nexts){
      if(es[i].to==pre){
        continue;
      }
      opera.push_back({es[i].to,root,depth+es[i].length});
    }
  }
  return;
}
int main(void){
  ll n;
  cin>>n;
  vii s(n,vi(n));
  rep(i,n)rep(j,n){
    char tmp;
    cin>>tmp;
    s[i][j]=tmp-'0';
  }
  createtreenode(n);
  rep(i,n)rep(j,n){
    if(i<j && s[i][j]==1){
      insertree(1,i,j,-1);
    }
  }
  int ans=-1;
  rep(i,n){
    //cout<<"int "<<i<<endl;
    ngflag=0;
    tmpdepthmax=0;
    past=vi(n,-10);//0が未訪問
    BFS(i);
    if(ngflag==0){
      ans=max(ans,tmpdepthmax);
    }
  }
  if(ans==-1){
    cout<<-1<<endl;
  }else{
  cout<<ans+1<<endl;

  }
  return 0;
}


Measured memory_bytes: 2192