#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma comment(linker, "/stack:200000000")
 
#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long ll;
typedef unsigned long long ull;
typedef double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pdd;
 
#define X first
#define Y second
 
//#include <boost/unordered_map.hpp>
//using namespace boost;
 
/*
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> rbtree;
rbtree T;
*/
 
using i32 = int;
using i64 = long long;
using u8 = unsigned char;
using u32 = unsigned;
using u64 = unsigned long long;
using f64 = double;
using f80 = long double;
//using i128 = __int128_t;
//using u128 = __uint128_t;
//using i128 = i64;
//using u128 = u64;
 
ll power(ll a, ll b, ll p)
{
	if (!b) return 1;
	ll t = power(a, b/2, p);
	t = t*t%p;
	if (b&1) t = t*a%p;
	return t;
}
 
ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	ll px, py;
	ll d = exgcd(b, a%b, px, py);
	x = py;
	y = px-a/b*py;
	return d;
}

ll gcd(ll a, ll b)
{
	return b ? gcd(b, a%b) : a;
}
 
template<class T>
inline void freshmin(T &a, const T &b)
{
	if (a > b) a = b;
}
 
template<class T>
inline void freshmax(T &a, const T &b)
{
	if (a < b) a = b;
}

template<class T>
void print(const T &a)
{
	for (auto x : a) printf("%d ", x); puts("");
}

const int MAXN = 210;
const int MAXM = 30*30*16*16+10;
const int MAXK = 30;
//const i64 INF = 1000000000000000000LL;
const int INF = 1000000000;
//const int MOD = 998244353;
//const int MOD = 1000000007;
//const int INV2 = (MOD+1)/2;
const ld pi = 3.1415926535897932384626433;

int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};

#define rep(i,a,b) for (int i = (a), I = (b); i <= I; ++ i)

struct undirected_graph
{
	int n;
	vector<pii> edge;
	undirected_graph (int n)
	{
		init(n);
	}
	void init(int n)
	{
		assert(n >= 0);
		this->n = n;
	}
	void addedge(int x, int y)
	{
		assert(1 <= x && x <= n);
		assert(1 <= y && y <= n);
		edge.push_back({x, y});
	}
	
	vector<vector<int>> v;
	vector<int> d;
	int go(int s)
	{
		v = vector<vector<int>>(n+1);
		for (auto e : edge)
		{
			int x = e.X, y = e.Y;
			v[x].push_back(y);
			v[y].push_back(x);
		}
		d = vector<int>(n+1, INF);
		queue<int> Q;
		Q.push(s);
		d[s] = 0;
		while (!Q.empty())
		{
			int x = Q.front();
			Q.pop();
			for (auto y : v[x])
				if (d[y] > d[x]+1)
				{
					d[y] = d[x]+1;
					Q.push(y);
				}
		}
		int ret = 1;
		for (int i = 1; i <= n; ++ i)
			if (d[i] != INF && d[i] > d[ret]) ret = i;
		return ret;
	}
};

struct tree
{
	const static int K = 10; // for LCA
	int n;
	vector<vector<int>> v;
	tree (const undirected_graph &G)
	{
		n = G.n;
		v = vector<vector<int>>(n+1);
		for (auto e : G.edge)
		{
			int x = e.X, y = e.Y;
			v[x].push_back(y);
			v[y].push_back(x);
		}
	}
	
	vector<int> r;
	int times;
	vector<int> X, Y;
	vector<int> dis;
	vector<array<int, K>> pre;
	void dfs(int x, int p)
	{
		X[x] = ++ times;
		for (auto y : v[x])
		{
			if (y == p) continue;
			dis[y] = dis[x]+1;
			pre[y][0] = x;
			dfs(y, x);
		}
		Y[x] = times;
	}
	void build_dfs_order(int root)
	{
		assert(1 <= root && root <= n);
		r = vector<int>(n+1);
		X = vector<int>(n+1);
		Y = vector<int>(n+1);
		dis = vector<int>(n+1);
		pre = vector<array<int, K>>(n+1);
		times = 0;
		dfs(root, 0);
		for (int k = 1; k < K; ++ k)
			for (int i = 1; i <= n; ++ i)
				pre[i][k] = pre[pre[i][k-1]][k-1];
	}
	
	int getLCA(int x, int y)
	{
		assert(n <= 1<<K);
		if (dis[x] < dis[y]) swap(x, y);
		for (int k = K-1; k >= 0; -- k)
			if (dis[x]-dis[y] >= 1<<k)
				x = pre[x][k];
		if (x == y) return x;
		for (int k = K-1; k >= 0; -- k)
			if (pre[x][k] != pre[y][k])
			{
				x = pre[x][k];
				y = pre[y][k];
			}
		return pre[x][0];
	}
};

int n;
char s[MAXN][MAXN];

int F[MAXN];

int father(int x)
{
	return F[x] == x ? x : F[x] = father(F[x]);
}

void solve()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i)
		scanf(" %s", s[i]+1);
	undirected_graph G(n);
	for (int x = 1; x <= n; ++ x)
		for (int y = x+1; y <= n; ++ y) if (s[x][y] == '1')
		{
			G.addedge(x, y);
		}
	int ans = 1;
	for (int s = 1; s <= n; ++ s)
	{
		int t = G.go(s);
		int len = G.d[t];
		int flag = 0;
		for (int x = 1; x <= n; ++ x)
			for (int y = x+1; y <= n; ++ y)
				if (::s[x][y] == '1')
					if (abs(G.d[x]-G.d[y]) != 1) flag = 1;
		if (!flag) freshmax(ans, len+1);
	}
	if (ans <= 1) ans = -1;
	cout << ans << endl;
}

int main()
{
	
	int T;
	T = 1;
	//scanf("%d", &T);
	while (T --)
	solve();
	
	return 0;
}


Measured memory_bytes: 640