#include<iostream>
#include<string>
#include<iomanip>
#include<cmath>
#include<vector>
#include<algorithm>
#include<queue>

using namespace std;

#define int long long
#define endl "\n"

const long long INF = (long long)1e18;
const long long MOD = 1'000'000'007; 

string yn(bool f){return f?"Yes":"No";}
string YN(bool f){return f?"YES":"NO";}

class union_find
{
	int  _setnum;
	vector<int> par, nume;
public:
	union_find(){
	}
	
	union_find(int x){
		par.resize(x);
		nume.resize(x);
		init();
	}
	
	~union_find(){
		//
		
	}
	
	void clear(){
		_setnum = 0;
		par.clear();
		nume.clear();
	}
	
	void init(){
		_setnum = par.size();
		for(int i = 0; i < par.size(); i++){
			par[i] = i;
			nume[i] = 1;
		}
	}
	
	void resize(int x){
		
		par.resize(x);
		nume.resize(x);
		init();
	}

	int find(int x){
		return par[x] == x ? x : par[x] = find(par[x]);
	}

	void unite(int x, int y){
		x = find(x);
		y = find(y);
	
		if(x == y)return;
		
		_setnum--;
		
		if(nume[x] > nume[y]) std::swap(x,y);
		
		par[x] = y;
		nume[y] += nume[x];
	}
	
	bool same(int x, int y){
		return find(x) == find(y);
	}
	
	int numel(int x){
		return nume[find(x)];
	}
	
	int size(){
		return par.size();
	}
	
	int setnum(){
		return _setnum;
	}
};

int check(vector<vector<int>> &G, int now){
	queue<pair<int,int>> Q;
	vector<int> dis(G.size(), INF);
	vector<pair<int,int>> x;
	vector<int> used(G.size());
	union_find uf(G.size());
	int res = 0;
	
	
	
	for(int i = 0; i < G[now].size(); i++){
		int node = G[now][i];
		Q.push(make_pair(node, 1));
		dis[node] = 1;
		// cout<<"i = "<<i<<endl;
		// cout<<"now "<<now<<" node "<<node<<endl;
	}
	
	dis[now] = 0;
	
	while(!Q.empty()){
		pair<int,int> p = Q.front(); Q.pop();
		
		if(p.first == now) continue;
		
		if(dis[p.first] < p.second) continue;
		
		// cout<<"X"<<" "<<p.first<<" "<<p.second<<endl;
		
		bool flag = true;
		
		for(int next : G[p.first]){
			
			if(dis[next] == p.second) return -1;
			
			// cout<<"next "<<next<<endl;
			
			if(next != now)uf.unite(next, p.first);
			
			if(dis[next] > p.second + 1){
				dis[next] = p.second + 1;
				
				Q.push(make_pair(next, p.second + 1));
			}
			if(dis[next] > p.second) flag = false;
		}
		
		if(flag){
			// cout<<"flag "<<p.first<<" "<<p.second<<endl;
			x.push_back(make_pair(p.second,p.first));
		}
	}
	
	sort(x.begin(), x.end(), greater<pair<int,int>>());
	
	// if(x.size() == 0){
		// return 1;
	// } else if(x.size() == 1){
		// return x[0] + 1;
	// } else {
		// cout<<"<><> "<<x[0] + x[1] + 1<<endl;
		// return x[0] + x[1] + 1;
	// }
	
	res = 1;
	
	for(int i = 0, con = 0; i < x.size(); i++){
		if(used[uf.find(x[i].second)]) continue;
		used[uf.find(x[i].second)] = true;
		// cout<<uf.find(x[i].second)<<endl;
		res += x[i].first;
		con++;
		if(con == 2) break;
	}
	
	// cout<<"res "<<res<<endl;
	return res;
}

int solve(vector<string> &s){
	int N = s.size();
	int res = -1;
	
	vector<vector<int>> G(N);
	
	for(int i = 0; i < N; i++){
		for(int j = 0; j < N; j++){
			if(s[i][j] == '1'){
				if(i == j) return -1;
				
				G[i].push_back(j);
				// G[j].push_back(i);
			}
		}
	}
	
	for(int i = 0; i < N; i++){
		res = max(check(G, i), res);
	}
	
	return res;
}

signed main(){
	cin.tie(nullptr);
	ios::sync_with_stdio(false);
	cout<<fixed<<setprecision(10);
	
	int N;
	vector<string> s;
	
	cin>>N;
	
	s.resize(N);
	
	for(int i = 0; i < N; i++){
		cin>>s[i];
	}
	
	cout<<solve(s)<<endl;
	
	return 0;
}

Measured memory_bytes: 768