unittest
{
	assert( [ "2", "01", "10" ].parse.expand.solve == 2 );
	assert( [ "3", "011", "101", "110" ].parse.expand.solve == -1 );
	assert( [ "6", "010110", "101001", "010100", "101000", "100000", "010000" ].parse.expand.solve == 4 );
}



import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto n = input.front.to!( long );
	auto sss = new long[][]( n, n );
	foreach( ref ss; sss )
	{
		input.popFront;
		foreach( ref s, a; lockstep( ss, input.front ) )
		{
			s = a - '0';
		}
	}
	return tuple( n, sss );
}

auto solve( long n, long[][] sss )
{
	// 二部グラフにできるか判定
	auto uft = UnionFindTree( sss.length * 2 );
	foreach( i, ss; sss )
	{
		foreach( j, s; ss )
		{
			if( s != 1 ) continue;
			uft.unite( i,     j + n );
			uft.unite( i + n, j     );
		}
	}
	foreach( i; 0L .. n )
	{
		if( uft.same( i, i + n ) ) return -1;		// むり
	}
	
	// 二部グラフをn部グラフに広げるときの最大のnを計算（一番遠い頂点間の距離+1がnになる）
	auto ans = 0L;
	foreach( i, ref ss; sss )
	{
		foreach( j, ref s; ss )
		{
			if( i != j && s == 0 ) s = long.max;
		}
	}
	warshallfloyd( sss );
	foreach( ss; sss )
	{
		foreach( s; ss )
		{
			if( s == long.max ) continue;
			ans = max( ans, s + 1 );
		}
	}
	return ans;
}

// UnionFind木
struct UnionFindTree
{
	long[] ps;
	long[] rs;
	
	this( long n )
	{
		ps.length = n;
		ps[] = -1;
		rs.length = n;
	}
	
	long root( long i )
	{
		if( ps[ i ] < 0 ) return i;
		else              return ps[ i ] = root( ps[ i ] );
	}
	
	auto same( long i, long j )
	{
		return root( i ) == root( j );
	}
	
	void unite( long i, long j )
	{
		i = root( i );
		j = root( j );
		if( i == j ) return;
		if( rs[ i ] < rs[ j ] )
		{
			ps[ j ] += ps[ i ];
			ps[ i ] = j;
		}
		else
		{
			ps[ i ] += ps[ j ];
			ps[ j ] = i;
			if( rs[ i ] == rs[ j ] ) rs[ i ]++;
		}
	}
}

// 正負の重み付きグラフの全二点間最短経路探索（ワーシャルフロイド法）
auto warshallfloyd( ref long[][] dss )
{
	foreach( p; 0L .. dss.length )
	{
		foreach( f; 0L .. dss.length )
		{
			foreach( t; 0L .. dss.length )
			{
				if( dss[ f ][ p ] == long.max || dss[ p ][ t ] == long.max ) continue;
				dss[ f ][ t ] = min( dss[ f ][ t ], dss[ f ][ p ] + dss[ p ][ t ] );
			}
		}
	}
	return dss;
}
