"""

AtCoder Grand Contest 039  B - Graph Partition / 





（１）ある集合V_iに含まれるノードから伸びる辺について、その先の集合がV_i-1かV_i+1になるように分ける

（２）その時の集合の個数の最大値を求める



（１）を言い換えると、あるノードが偶数番の集合に属しているとき、それと繋がっているノードが奇数番号の集合かつ差が１である

　→二部グラフ

（２）V_1とV_kがあるとき、少なくともそれらはk本の辺をたどらなければ繋がれないはずなので、最も距離の長い辺（直径）を探す

"""



from collections import deque



N = int(eval(input()))

es = [[] for _ in range(N)]



for i in range(N):

    S = eval(input())

    for j in range(N):

        if S[j] == "1":

            es[i].append(j)





q = deque()

q.append(0)

checked = [0] * N

checked[0] = 1

while q:

    curr = q.popleft()

    for nxt in es[curr]:

        # 未探索なので、currと別の集合に設定

        if checked[nxt] == 0:

            checked[nxt] = checked[curr] * -1

            q.append(nxt)

        else:

            # 探索済みなので、別の集合に属しているか確認し、同じであれば条件を満たさない

            if checked[nxt] == checked[curr]:

                print((-1))

                exit()







# グラフの直径を求める。それぞれのノードをスタート地点として、全ノード間の距離を求めたときの最大距離が直径

ans = 0

for i in range(N):

    q = deque()

    q.append(i)

    dist = [0] * N

    # 距離＋１が答えなので、起点を１としておく

    dist[i] = 1

    while q:

        curr = q.popleft()

        for nxt in es[curr]:

            if dist[nxt] == 0:

                dist[nxt] = dist[curr] + 1

                q.append(nxt)



    ans = max(ans, max(dist))



print(ans)
"""

問題の理解が困難

ノードi,jを結ぶ辺があるとき、ノードiは集合aに、ノードjは集合k+1（あるいは逆）に含まれるようにノードを集合に分ける。

その条件を満たす最大の集合の数を求める



1->2

2->3

2->4

みたいなのがあるときに、

・1と2は別の集合（1を集合１、２を集合とする）

・２と３は別の集合（２が集合２なので、３は集合１か３。できるだけ集合の数を多くとりたいので、３とする）

・２と４は別の集合（２が集合２なので、４は集合１か３。上に同じく３とする）

みたいな感じか。

なので、

あるノードから等距離にあるノードを同じ集合にする

という戦略をとれば、集合の数を最大化できる。

で、同じ集合に属するやつらの間に辺がある場合、辺を挟んだノードは別の集合にならなければならないので矛盾するからNG



↑から、木の直径＋１が最大の集合数になるので、double sweepだったか？何かでもとめればよいか？

"""







import heapq

from collections import deque







N = int(eval(input()))

S = [eval(input()) for _ in range(N)]

es = [[] for _ in range(N)]



for i in range(N):

    for j in range(i+1,N):

        if S[i][j] == "1":

            es[i].append(j)

            es[j].append(i)





INF = float("inf")

dist = [INF] * N

dist[0] = 0

union = [[] for _ in range(N+1)]

union[0].append(0)

q = []

heapq.heappush(q, (0, 0))



while q:

    cost, curr = heapq.heappop(q)

    for nxt in es[curr]:

        if dist[nxt] <= cost + 1:

            continue

        dist[nxt] = cost + 1



        union[cost+1].append(nxt)

        heapq.heappush(q, (dist[nxt], nxt))





for u in union:

    if len(u) >= 2:

        for i in u:

            for j in u:

                # 同じ集合なのに辺があると矛盾するのでNG

                if S[i][j] == "1":



                    print((-1))

                    exit()



ans = 0

for i in range(N):

    q = deque()

    q.append(i)

    dist = [0] * N

    # 距離＋１が答えなので、起点を１としておく

    dist[i] = 1

    while q:

        curr = q.popleft()

        for nxt in es[curr]:

            if dist[nxt] == 0:

                dist[nxt] = dist[curr] + 1

                q.append(nxt)

 

    ans = max(ans, max(dist))



print(ans)
"""
AtCoder Grand Contest 039  B - Graph Partition / 
（１）ある集合V_iに含まれるノードから伸びる辺について、その先の集合がV_i-1かV_i+1になるように分ける
（２）その時の集合の個数の最大値を求める
（１）を言い換えると、あるノードが偶数番の集合に属しているとき、それと繋がっているノードが奇数番号の集合かつ差が１である
　→二部グラフ
（２）V_1とV_kがあるとき、少なくともそれらはk本の辺をたどらなければ繋がれないはずなので、最も距離の長い辺（直径）を探す
"""
from collections import deque

N = int(eval(input()))
es = [[] for _ in range(N)]
for i in range(N):
    S = eval(input())
    for j in range(N):
        if S[j] == "1":
            es[i].append(j)
q = deque()
q.append(0)
checked = [0] * N
checked[0] = 1
while q:
    curr = q.popleft()
    for nxt in es[curr]:
        # 未探索なので、currと別の集合に設定
        if checked[nxt] == 0:
            checked[nxt] = checked[curr] * -1
            q.append(nxt)
        else:
            # 探索済みなので、別の集合に属しているか確認し、同じであれば条件を満たさない
            if checked[nxt] == checked[curr]:
                print((-1))
                exit()
# グラフの直径を求める。それぞれのノードをスタート地点として、全ノード間の距離を求めたときの最大距離が直径
ans = 0
for i in range(N):
    q = deque()
    q.append(i)
    dist = [0] * N
    # 距離＋１が答えなので、起点を１としておく
    dist[i] = 1
    while q:
        curr = q.popleft()
        for nxt in es[curr]:
            if dist[nxt] == 0:
                dist[nxt] = dist[curr] + 1
                q.append(nxt)
    ans = max(ans, max(dist))
print(ans)

"""
問題の理解が困難
ノードi,jを結ぶ辺があるとき、ノードiは集合aに、ノードjは集合k+1（あるいは逆）に含まれるようにノードを集合に分ける。
その条件を満たす最大の集合の数を求める
1->2
2->3
2->4
みたいなのがあるときに、
・1と2は別の集合（1を集合１、２を集合とする）
・２と３は別の集合（２が集合２なので、３は集合１か３。できるだけ集合の数を多くとりたいので、３とする）
・２と４は別の集合（２が集合２なので、４は集合１か３。上に同じく３とする）
みたいな感じか。
なので、
あるノードから等距離にあるノードを同じ集合にする
という戦略をとれば、集合の数を最大化できる。
で、同じ集合に属するやつらの間に辺がある場合、辺を挟んだノードは別の集合にならなければならないので矛盾するからNG
↑から、木の直径＋１が最大の集合数になるので、double sweepだったか？何かでもとめればよいか？
"""
import heapq
from collections import deque

N = int(eval(input()))
S = [eval(input()) for _ in range(N)]
es = [[] for _ in range(N)]
for i in range(N):
    for j in range(i + 1, N):
        if S[i][j] == "1":
            es[i].append(j)
            es[j].append(i)
INF = float("inf")
dist = [INF] * N
dist[0] = 0
union = [[] for _ in range(N + 1)]
union[0].append(0)
q = []
heapq.heappush(q, (0, 0))
while q:
    cost, curr = heapq.heappop(q)
    for nxt in es[curr]:
        if dist[nxt] <= cost + 1:
            continue
        dist[nxt] = cost + 1
        union[cost + 1].append(nxt)
        heapq.heappush(q, (dist[nxt], nxt))
for u in union:
    if len(u) >= 2:
        for i in u:
            for j in u:
                # 同じ集合なのに辺があると矛盾するのでNG
                if S[i][j] == "1":
                    print((-1))
                    exit()
ans = 0
for i in range(N):
    q = deque()
    q.append(i)
    dist = [0] * N
    # 距離＋１が答えなので、起点を１としておく
    dist[i] = 1
    while q:
        curr = q.popleft()
        for nxt in es[curr]:
            if dist[nxt] == 0:
                dist[nxt] = dist[curr] + 1
                q.append(nxt)
    ans = max(ans, max(dist))
print(ans)

-AtCoder Grand Contest 039  B - Graph Partition / -（１）ある集合V_iに含まれるノードから伸びる辺について、その先の集合がV_i-1かV_i+1になるように分ける -（２）その時の集合の個数の最大値を求める -（１）を言い換えると、あるノードが偶数番の集合に属しているとき、それと繋がっているノードが奇数番号の集合かつ差が１である -　→二部グラフ -（２）V_1とV_kがあるとき、少なくともそれらはk本の辺をたどらなければ繋がれないはずなので、最も距離の長い辺（直径）を探す +問題の理解が困難 +ノードi,jを結ぶ辺があるとき、ノードiは集合aに、ノードjは集合k+1（あるいは逆）に含まれるようにノードを集合に分ける。 +その条件を満たす最大の集合の数を求める +1->2 +2->3 +2->4 +みたいなのがあるときに、 +・1と2は別の集合（1を集合１、２を集合とする） +・２と３は別の集合（２が集合２なので、３は集合１か３。できるだけ集合の数を多くとりたいので、３とする） +・２と４は別の集合（２が集合２なので、４は集合１か３。上に同じく３とする） +みたいな感じか。 +なので、 +あるノードから等距離にあるノードを同じ集合にする +という戦略をとれば、集合の数を最大化できる。 +で、同じ集合に属するやつらの間に辺がある場合、辺を挟んだノードは別の集合にならなければならないので矛盾するからNG +↑から、木の直径＋１が最大の集合数になるので、double sweepだったか？何かでもとめればよいか？ +import heapq +S = [eval(input()) for _ in range(N)] -    S = eval(input()) -    for j in range(N): -        if S[j] == "1": +    for j in range(i + 1, N): +        if S[i][j] == "1": -q = deque() -q.append(0) -checked = [0] * N -checked[0] = 1 +            es[j].append(i) +INF = float("inf") +dist = [INF] * N +dist[0] = 0 +union = [[] for _ in range(N + 1)] +union[0].append(0) +q = [] +heapq.heappush(q, (0, 0)) -    curr = q.popleft() +    cost, curr = heapq.heappop(q) -        # 未探索なので、currと別の集合に設定 -        if checked[nxt] == 0: -            checked[nxt] = checked[curr] * -1 -            q.append(nxt) -        else: -            # 探索済みなので、別の集合に属しているか確認し、同じであれば条件を満たさない -            if checked[nxt] == checked[curr]: -                print((-1)) -                exit() -# グラフの直径を求める。それぞれのノードをスタート地点として、全ノード間の距離を求めたときの最大距離が直径 +        if dist[nxt] <= cost + 1: +            continue +        dist[nxt] = cost + 1 +        union[cost + 1].append(nxt) +        heapq.heappush(q, (dist[nxt], nxt)) +for u in union: +    if len(u) >= 2: +        for i in u: +            for j in u: +                # 同じ集合なのに辺があると矛盾するのでNG +                if S[i][j] == "1": +                    print((-1)) +                    exit()