import java.io.*
import java.util.*
import java.lang.*
import java.lang.Math.*


class Bipartite(val eg: Array<ArrayList<Int>>) {
    private var paintable = true
    private lateinit var col: IntArray
    private fun dfs(x: Int, c: Int) {
        col[x] = c
        val nc = (c+1)%2
        for (nx in eg[x]) {
            if (col[nx] >= 0) {
                if (col[nx] == nc) continue
                else {
                    paintable = false
                    return
                }
            }
            dfs(nx, nc)
        }
    }
    fun isBipartite(): Boolean {
        val N = eg.size
        for (i in 0 until N) {
            this.paintable = true
            col = IntArray(N){-1}
            dfs(i, 0)
            if (!paintable) return false
        }
        return true
    }
}

class Warshall(val eg: Array<ArrayList<Int>>, val unidirectional: Boolean = false) {
    private val N = eg.size
    private val dist = Array(N){LongArray(N){LINF}}
    init {
        for (i in 0 until N) {
            dist[i][i] = 0
        }
        for (s in 0 until N) {
            for (t in eg[s]) {
                dist[s][t] = 1L
                if (!unidirectional) {
                    dist[t][s] = 1L
                }
            }
        }
        for (k in 0 until N) {
            for (i in 0 until N) {
                if (dist[i][k] == LINF) continue
                for (j in 0 until N) {
                    if (dist[k][j] == LINF) continue
                    if (dist[i][j] > dist[i][k] + dist[k][j]) {
                        dist[i][j] = dist[i][k] + dist[k][j]
                    }
                }
            }
        }
    }
    fun distance(i: Int, j: Int): Long {
        return if (hasNegativeCycle(i,j)) -LINF else dist[i][j]
    }
    fun hasNegativeCycle(s: Int, t: Int): Boolean {
        return dist[s][t] < 0
    }
    fun hasNegativeCycle(): Boolean {
        val N = dist.size
        var res = false
        for(i in 0 until N) {
            if (dist[i][i] < 0) {
                res = true
                break
            }
        }
        return res
    }
}

fun solve() {
    val N = rd.readInt()
    val S = (0 until N).map{rd.readString()}

    val eg = Array(N){ArrayList<Int>()}
    S.forEachIndexed{i, row->
        row.forEachIndexed{j, ch->
            if (ch == '1') {
                eg[i].add(j)
                eg[j].add(i)
            }
        }
    }

    val bp = Bipartite(eg)
    if (!bp.isBipartite()) {
        println(-1)
        return
    }

    val ws = Warshall(eg)
    var diameter = 0L
    for (i in 0 until N) {
        for (j in i + 1 until N) {
            diameter = max(diameter, ws.distance(i,j))
        }
    }

    val ans = diameter + 1L
    println(ans)
}


//val rd = debug.Reader("agc", "039", "b", "sample-1")
val rd = Reader()


fun main(args: Array<String>) {
    try {
        var exception: Throwable? = null
        val sth = Thread(null, SolveThread(), "solveThread", 128 * 1024 * 1024)
        sth.setUncaughtExceptionHandler { _, e -> exception = e }
        sth.start(); sth.join()
        if (exception != null) throw exception!! }
    catch (e: Exception) { throw e }
    finally { rd.close() }
}
const val MOD = 1_000_000_007L; const val INF = Int.MAX_VALUE/2; const val LINF = Long.MAX_VALUE/2
data class IntPair(val first: Int, val second: Int); data class LongPair(val first: Long, val second: Long)
data class To(val idx: Int, val cost: Long)
val errPrintln: (Any) -> Unit = { msg -> System.err.println(msg) }
fun rAssert(exp: Boolean, lazyMsg: () -> String = {""}) {
    if (!exp) { val msg = lazyMsg(); errPrintln("EAssert Error: $msg"); throw Error(msg) }
}
fun tAssert(exp: Boolean, lazyMsg: () -> String = {""}) {
    if (!exp) { val msg = lazyMsg(); errPrintln("TAssert Error: $msg"); Thread.sleep(3000) }
}
class SolveThread : Runnable {
    override fun run() { solve() }
}
class Reader {
    private val br = BufferedReader(InputStreamReader(System.`in`))
    val readString: () -> String = { br.readLine() }
    val readInt: () -> Int = { br.readLine().toInt() }
    val readLong: () -> Long = { br.readLine().toLong() }
    val readIntArray: () -> IntArray = { br.readLine().split(' ').map { it.toInt() }.toIntArray() }
    val readLongArray: () -> LongArray = { br.readLine().split(' ').map { it.toLong() }.toLongArray() }
    val readListInt: () -> List<Int> = { br.readLine().split(' ').map { it.toInt() } }
    val readListLong: () -> List<Long> = { br.readLine().split(' ').map { it.toLong() } }
    val readListIntCol: (Int) -> List<Int> = { N -> (0 until N).map { readInt() } }
    val readListLongCol: (Int) -> List<Long> = { N -> (0 until N).map { readLong() } }
    val close: () -> Unit = { br.close() }
    protected fun finalize() { close() }
}


Measured memory_bytes: 39088