#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<iomanip>
#include<climits>
#include<string>
#include<sstream>
#include<numeric>
#define MOD 1000000007
#define in2d(i,j,H,W)(0<=i&&i<H&&0<=j&&j<W)

using namespace std;

typedef pair<int,int> pii;
typedef long long ll;

struct edge{
	int from,to,d,c;
	edge(int _from=0,int _to=0,int _d=0,int _c=0){
		from=_from;
		to=_to;
		d=_d;
		c=_c;
	}
	bool operator<(const edge &rhs)const{
		return (d==rhs.d)?(c<rhs.c):(d<rhs.d);
	}
};
typedef vector<edge> edges;
typedef vector<edges> graph;

ll gcd(ll a,ll b){
	if(b==0)return a;
	else return gcd(b,a%b);
}
ll factorial(ll x){
	if(x==1)return 1;
	else return x*factorial(x-1);
}
ll pow(ll x,int n){
	if(n==0)return 1;
	ll ret=(n&1)?x:1;
	ll a=pow(x,n/2);
	return ret*a*a;
}
struct UFT{
	vector<int>par;
	int getpar(int i){
		if(par[i]==i)return i;
		return par[i]=getpar(par[i]);
	}
	void unite(int i,int j){
		int t=getpar(i);
		par[t]=getpar(j);
	}
	bool uf(int i,int j){
		return getpar(i)==getpar(j);
	}
	UFT(int n){
		par=vector<int>(n);
		for(int i=0;i<n;i++)par[i]=i;
	}
	~UFT(){
		delete &par;
	}
};
struct SegT{
	vector<ll>container;
	int n;
	void update(int i,ll x){
		int ii=i+n-1;
		container[ii]=x;
		while(ii>0){
			ii=(ii-1)/2;
			//////////////////////////////////////////
			container[ii]=max(container[2*ii+1],container[2*ii+2]);
			//////////////////////////////////////////
		}
	}
	ll get(int l,int r,int l2=0,int r2=-1,int k=0){
		if(r2==-1)r2=n;
		///////////////////////////////////
		if(r2<=l||r<=l2)return 0;
		///////////////////////////////////
		if(l<=l2&&r2<=r)return container[k];
		ll vl=get(l,r,l2,(l2+r2)/2,2*k+1);
		ll vr=get(l,r,(l2+r2)/2,r2,2*k+2);
		///////////////////////////
		return max(vl,vr);
		///////////////////////////
	}
	////////////////new///////////////////////
	SegT(vector<int> &A){
		n=pow(2,(int)log2(A.size())+1);
		container=vector<ll>(2*n,0);
		for(int i=0;i<A.size();i++)update(i,A[i]);
	}
	~SegT(){
		delete &container;
	}

};
void dijkstra(graph &G,vector<int>&d,int s){
	d=vector<int>(G.size(),INT_MAX/2);
	priority_queue<pii,vector<pii >,greater<pii > >q;
	d[s]=0;q.push(pii(0,s));
	while(!q.empty()){
		pii p=q.top();q.pop();
		if(d[p.second]<p.first)continue;
		for(int i=0;i<G[p.second].size();i++){
			edge e=G[p.second][i];
			if(p.first+e.d<d[e.to]){
				d[e.to]=p.first+e.d;
				q.push(pii(d[e.to],e.to));
			}
		}
	}
}
int minT(edges &es,int n){
	sort(es.begin(),es.end());
	int ret=0;
	UFT *u=new UFT(n);
	for(int i=0;i<es.size();i++){
		edge e=es[i];
		if(u->uf(e.from,e.to))continue;
		ret+=e.d;
		u->unite(e.from,e.to);
	}
	for(int i=1;i<n;i++)if(!u->uf(0,i))return -1;
	return ret;
}
vector<int>d;
int N;
int main(){
	cout<<fixed<<setprecision(11);
	cin>>N;
	vector<string>S(N);
	for(int i=0;i<N;i++)cin>>S[i];
	int ans=0;
	for(int i=0;i<N;i++){
		d=vector<int>(N,20000);
		d[i]=0;
		queue<int>q;
		q.push(i);
		while(!q.empty()){
			int p=q.front();q.pop();
			for(int i=0;i<N;i++)if(S[p][i]=='1'){
				if(d[i]==20000){
					q.push(i);
					d[i]=d[p]+1;
				}else{
					if(d[i]%2==d[p]%2){
						ans=-1;
						cout<<ans<<endl;
						return 0;
					}else{
						if(d[i]>d[p]+1){
							d[i]=d[p]+1;
							q.push(i);
						}
					}
				}
			}
		}
		for(int j=0;j<N;j++)ans=max(ans,d[j]);
	}
	cout<<ans+1<<endl;
	return 0;
}



Measured memory_bytes: 256