#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cfloat>

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

typedef  std::pair<int,int> P;

template<typename CostType>
/// \brief 辺の情報
struct Edge{
  int      to;
  CostType cost;

  Edge(int t, CostType c): to(t), cost(c){
  }
};

template<typename CostType>
class Graph{

private:

  /// \brief adjacent_list_[n]=ノードnの隣接リストを表すvector<Edge>
  std::vector<std::vector<Edge<CostType>>> adjacent_list_;

public:

  /// \brief 頂点数
  const int NODE_SIZE_;

  /// \brief コンストラクタ
  /// \param node_size 頂点数
  explicit Graph(const int node_size): NODE_SIZE_(node_size),
                                       adjacent_list_(node_size){
  }

  /// \brief 有向グラフの辺を生やす
  /// \param from 辺の根本の頂点の番号
  /// \param to 辺の先の頂点の番号
  /// \param cost 辺のコスト
  void SetDirectedEdge(const int from, const int to, const CostType cost){
    adjacent_list_[from].push_back(Edge<CostType>(to, cost));
  }

  /// \brief 無向グラフの辺を生やす
  /// \param node_a 一方の頂点の番号
  /// \param node_b もう一方の頂点の番号
  /// \param cost 辺のコスト
  void
  SetUndirectedEdge(const int node_a, const int node_b, const CostType cost){
    SetDirectedEdge(node_a, node_b, cost);
    SetDirectedEdge(node_b, node_a, cost);
  }

  /// \brief ある頂点の隣接リストを取得
  /// \param node_num 頂点の番号
  /// \return 隣接リスト
  std::vector<Edge<CostType>> GetAdjacentList(int node_num) const{
    return adjacent_list_[node_num];
  }
};


int main(void){
  cout << std::fixed << std::setprecision(16);
  cin.tie(0);
  std::ios::sync_with_stdio(false);

  int n;
  cin>>n;
  bool hasEdge[201][201]={};
  for(int r=1;r<=n;r++){
    std::string s;
    cin>>s;
    for(int c=1;c<=n;c++){
      if(s[c-1]=='1'){
        hasEdge[r][c]=true;
      }
    }
  }
  Graph<int> graph(n+1);
  for(int i=1;i<=n;i++){
    for(int j=i+1;j<=n;j++){
      if(hasEdge[i][j]){
        graph.SetUndirectedEdge(i,j,1);
      }
    }
  }

  int result=-1;
  for(int start=1;start<=n;start++){

    int  depth[201]={};
    bool visited[201]={};
    std::queue<std::pair<int,int>> q;
    bool isOK=true;
    q.push(std::make_pair(start,1));
    while(!q.empty()){
      P curr=q.front();
      q.pop();
      visited[curr.first]=true;
      if(depth[curr.first]==0){
        depth[curr.first]=curr.second;
      }else{
        if(depth[curr.first]!=curr.second){
          isOK=false;
          break;
        }
      }
      for(auto n:graph.GetAdjacentList(curr.first)){
        if(!visited[n.to]){
          visited[n.to]=true;
          q.push(std::make_pair(n.to,curr.second+1));
        }

      }
    }

    bool isValid=true;
    if(isOK){
      for(int i=1;i<=n;i++){
        for(auto n:graph.GetAdjacentList(i)){
          if(std::abs(depth[i]-depth[n.to])!=1){
            isValid=false;
            break;
          }
        }
        if(!isValid) break;
      }
      if(isValid){
        int tmp_max=-1;
        for(int i=1;i<=n;i++){
          tmp_max=std::max(tmp_max,depth[i]);
        }
        result=std::max(result,tmp_max);
      }

    }

  }
  cout<<result<<endl;




  return 0;
}


Measured memory_bytes: 768