### BUGGY CODE ###

n = int(input())
s = []
for i in range(n):
    line = list(map(int, list(input())))
    s.append(line)

ans = -1

# @GDaigo さんのコメントより関数の追加 2017/03/18
def get_target_min_index(min_index, distance, unsearched_nodes):
    start = 0
    while True:
        index = distance.index(min_index, start)
        found = index in unsearched_nodes
        if found:
            return index
        else:
            start = index + 1

for k in range(n):
    unsearched_nodes = list(range(n)) # 未探索ノード
    distance = [300] * n # ノードごとの距離のリスト
    previous_nodes = [-1] * n # 最短経路でそのノードのひとつ前に到達するノードのリスト
    distance[k] = 0 # 初期のノードの距離は0とする

    while(len(unsearched_nodes) != 0): #未探索ノードがなくなるまで繰り返す
        # まず未探索ノードのうちdistanceが最小のものを選択する
        posible_min_distance = 300 # 最小のdistanceを見つけるための一時的なdistance。初期値は inf に設定。
        for node_index in unsearched_nodes: # 未探索のノードのループ
            if posible_min_distance > distance[node_index]: 
                posible_min_distance = distance[node_index] # より小さい値が見つかれば更新
        target_min_index = get_target_min_index(posible_min_distance, distance, unsearched_nodes) # 未探索ノードのうちで最小のindex番号を取得
        unsearched_nodes.remove(target_min_index) # ここで探索するので未探索リストから除去

        target_edge = s[target_min_index] # ターゲットになるノードからのびるエッジのリスト
        for index, route_dis in enumerate(target_edge):
            if route_dis != 0:
                if distance[index] > (distance[ target_min_index] + route_dis):
                    distance[index] = distance[ target_min_index] + route_dis # 過去に設定されたdistanceよりも小さい場合はdistanceを更新
                    previous_nodes[index] =  target_min_index #　ひとつ前に到達するノードのリストも更新

    marubatu = 1
    for i in range(n-1):
        if marubatu == 0:
            break
        for j in range(i+1, n):
            if distance[i] == distance[j] and s[i][j] == 1:
                marubatu = 0
                break
    if marubatu == 1:
        ans = max(ans, len(list(set(distance))))

print(ans)

### FIXED CODE ###

n = int(input())
s = []
for i in range(n):
    line = list(map(int, list(input())))
    s.append(line)

ans = -1

# @GDaigo さんのコメントより関数の追加 2017/03/18
def get_target_min_index(min_index, distance, unsearched_nodes):
    start = 0
    while True:
        index = distance.index(min_index, start)
        found = index in unsearched_nodes
        if found:
            return index
        else:
            start = index + 1

for k in range(n):
    unsearched_nodes = list(range(n)) # 未探索ノード
    distance = [300] * n # ノードごとの距離のリスト
    previous_nodes = [-1] * n # 最短経路でそのノードのひとつ前に到達するノードのリスト
    distance[k] = 0 # 初期のノードの距離は0とする

    while(len(unsearched_nodes) != 0): #未探索ノードがなくなるまで繰り返す
        # まず未探索ノードのうちdistanceが最小のものを選択する
        posible_min_distance = 300 # 最小のdistanceを見つけるための一時的なdistance。初期値は inf に設定。
        for node_index in unsearched_nodes: # 未探索のノードのループ
            if posible_min_distance > distance[node_index]: 
                posible_min_distance = distance[node_index] # より小さい値が見つかれば更新
        target_min_index = get_target_min_index(posible_min_distance, distance, unsearched_nodes) # 未探索ノードのうちで最小のindex番号を取得
        unsearched_nodes.remove(target_min_index) # ここで探索するので未探索リストから除去

        target_edge = s[target_min_index] # ターゲットになるノードからのびるエッジのリスト
        for index, route_dis in enumerate(target_edge):
            if route_dis != 0:
                if distance[index] > (distance[ target_min_index] + route_dis):
                    distance[index] = distance[ target_min_index] + route_dis # 過去に設定されたdistanceよりも小さい場合はdistanceを更新
                    previous_nodes[index] =  target_min_index #　ひとつ前に到達するノードのリストも更新

    marubatu = 1
    for i in range(n-1):
        if marubatu == 0:
            break
        for j in range(i+1, n):
            if distance[i] == distance[j] and s[i][j] == 1:
                marubatu = 0
                break
    if marubatu == 1:
        ans = max(ans, len(list(set(distance))))

print(ans)