#include "bits/stdc++.h"
using namespace std;
#ifdef _DEBUG
#include "dump.hpp"
#else
#define dump(...)
#endif

//#define int long long
#define rep(i,a,b) for(int i=(a);i<(b);i++)
#define rrep(i,a,b) for(int i=(b)-1;i>=(a);i--)
#define all(c) begin(c),end(c)
const int INF = sizeof(int) == sizeof(long long) ? 0x3f3f3f3f3f3f3f3fLL : 0x3f3f3f3f;
const int MOD = 1'000'000'007;
template<class T> bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template<class T> bool chmin(T &a, const T &b) { if (b < a) { a = b; return true; } return false; }

template<typename T>
vector<T> gen_v(size_t a) { return vector<T>(a); }
template<typename T, typename ...Ts>
auto gen_v(size_t a, Ts... ts) { return vector<decltype(gen_v<T>(ts...))>(a, gen_v<T>(ts...)); }
template<typename T, typename V>
typename enable_if<is_class<T>::value == 0>::type
fill_v(T &t, const V &v) { t = v; }
template<typename T, typename V>
typename enable_if<is_class<T>::value != 0>::type
fill_v(T &t, const V &v) { for (auto &e : t) fill_v(e, v); }

using Weight = int;
struct Edge {
	int s, d; Weight w;
	Edge() {};
	Edge(int s, int d, Weight w) : s(s), d(d), w(w) {};
};
bool operator<(const Edge &e1, const Edge &e2) { return e1.w == e2.w ? (e1.s == e2.s ? e1.d < e2.d : e1.s < e2.s) : e1.w < e2.w; }
bool operator>(const Edge &e1, const Edge &e2) { return e2 < e1; }
inline ostream &operator<<(ostream &os, const Edge &e) { return (os << '(' << e.s << ", " << e.d << ", " << e.w << ')'); }

using Edges = vector<Edge>;
using Graph = vector<Edges>;
using Array = vector<Weight>;
using Matrix = vector<Array>;

void addArc(Graph &g, int s, int d, Weight w = 1) {
	g[s].emplace_back(s, d, w);
}
void addEdge(Graph &g, int a, int b, Weight w = 1) {
	addArc(g, a, b, w);
	addArc(g, b, a, w);
}

auto getEdges = [](const Graph &g) {
	Edges ret;
	for (auto &es : g)
		for (auto &e : es)
			ret.emplace_back(e);
	return ret;
};

auto bfs = [&](const Graph &g, int s, Array &dist) {
	int n = g.size();
	vector<bool> vis(n);
	vector<int> prev(n, -1);
	dist.assign(n, INF); dist[s] = 0;
	using State = tuple<Weight, int, int>;
	queue<State> q;
	q.emplace(0, s, -1);
	while (q.size()) {
		Weight d; int v, p; tie(d, v, p) = q.front(); q.pop();
		vis[v] = true;
		prev[v] = p;
		for (auto &e : g[v]) {
			if (vis[e.d])continue;
			if (dist[e.d] > dist[v] + e.w) {
				dist[e.d] = dist[v] + e.w;
				q.emplace(dist[e.d], e.d, v);
			}
		}
	}
	return prev;
};

struct UnionFind {
	vector<int> parent;
	int size;
	UnionFind(int n) :parent(n, -1), size(n) {}
	bool unite(int x, int y) {
		x = root(x); y = root(y);
		if (x == y)return false;
		if (sizeOf(x) < sizeOf(y))swap(x, y);
		parent[x] += parent[y]; parent[y] = x; size--;
		return true;
	}
	bool same(int x, int y) { return root(x) == root(y); }
	int root(int x) { return parent[x] < 0 ? x : parent[x] = root(parent[x]); }
	int sizeOf(int x) { return -parent[root(x)]; }
};

bool detectCycle(const Graph &g, int s = 0) {
	int n = g.size();
	vector<bool> vis(n);
	function<int(int, int)> dfs = [&](int u, int p) {
		bool ret = false;
		vis[u] = true;
		for (auto e : g[u]) {
			if (p == e.d)continue;
			if (vis[e.d])
				return true;
			ret |= dfs(e.d, u);
			if (ret)break;
		}
		return ret;
	};
	return dfs(s, -1);
}

signed main() {
	cin.tie(0);
	ios::sync_with_stdio(false);
	int n; cin >> n;
	vector<string> s(n);
	rep(i, 0, n) {
		cin >> s[i];
	}

	Graph g(n);
	set<pair<int, int>> st;
	rep(i, 0, n)rep(j, 0, n) {
		if (s[i][j] == '1') {
			addEdge(g, i, j);
		}
	}

	vector<bool> f(n);
	map<int, int> cnt;
	rep(i, 0, n) {
		int a = i;
		if (f[a])continue;
		f[a] = true;
		cnt[g[a].size()]++;
	}
	
	int ans = -1;
	rep(u, 0, n) {
		Array dist;
		bfs(g, u, dist);
		dump(dist);

		UnionFind uf(n);
		map<int, vector<int>> mp;
		rep(i, 0, dist.size()) {
			if (dist[i] == -1)continue;
			mp[dist[i]].push_back(i);
		}
		for (auto p : mp) {
			auto &v = p.second;
			for (auto x : v) {
				for (auto y : v) {
					if (x == y)continue;
					uf.unite(x, y);
				}
			}
		}
		bool ok = true;
		rep(i, 0, n)rep(j, 0, n) {
			if (s[i][j] == '1') {
				int a = uf.root(i);
				int b = uf.root(j);
				if (a == b)
					ok = false;
			}
		}
		if (ok) {
			chmax(ans, uf.size);
		}
	}
	cout << ans << endl;

	return 0;
}

Measured memory_bytes: 1536