Buggy python submission (verdict: Runtime Error):
import numpy as np
import sys
from scipy.sparse.csgraph import floyd_warshall, csgraph_from_dense
N = int(input())
S = np.frombuffer(sys.stdin.buffer.read(),
                  dtype='S1').reshape(N, -1)[:, :N].astype(int)
G = csgraph_from_dense(S)
F = floyd_warshall(G).astype(int)
F2 = F % 2
I0 = np.where(F2[0] == 0)
I1 = np.where(F2[0] == 1)
if (S[I0][:, I0] == 0).all() and (S[I1][:, I1] == 0).all():
    print(F.max() + 1)
    exit()
print(-1)


Fixed submission:
import numpy as np
import sys
from scipy.sparse.csgraph import floyd_warshall, csgraph_from_dense
N = int(sys.stdin.buffer.readline())
S = np.frombuffer(sys.stdin.buffer.read(),
                  dtype='S1').reshape(N, -1)[:, :N].astype(int)
G = csgraph_from_dense(S)
F = floyd_warshall(G).astype(int)
F2 = F % 2
I0 = np.where(F2[0] == 0)
I1 = np.where(F2[0] == 1)
if (S[I0][:, I0] == 0).all() and (S[I1][:, I1] == 0).all():
    print(F.max() + 1)
    exit()
print(-1)

Buggy python submission (verdict: Runtime Error):
import collections, itertools, sys
sys.setrecursionlimit(10**6)


class UnionFind():
    def __init__(self, size):
        self.dat = list(range(size))
        self.SIZE = [1] * size  # 0-indexed

    def find(self, x):
        dat = self.dat
        stack = [x]
        while True:
            y = stack[-1]
            if dat[y] != y:
                stack += [dat[y]]
            else:
                break
        for s in stack:
            dat[s] = y
        return y

    def unite(self, x, y):
        is_same = self.is_same
        find = self.find
        SIZE = self.SIZE
        dat = self.dat
        if not is_same(x, y):
            X, Y = find(x), find(y)
            SX, SY = SIZE[X], SIZE[Y]
            if SX > SY:
                m = dat[X] = Y
            else:
                m = dat[Y] = X
            SIZE[m] = SX + SY
            SIZE[X + Y - m] = 0

    def is_same(self, x, y):
        find = self.find
        return find(x) == find(y)

    def scan_uf(self):
        find = self.find
        length = len(self.dat)
        for i in range(length):
            find(i)

    def size(self, x):
        return self.SIZE[self.find(x)]


N = int(input())
S = [[int(_) for _ in input()] for _ in range(N)]
G = collections.defaultdict(set)
for i, j in itertools.product(range(N), repeat=2):
    if S[i][j]:
        G[i].add(j)
P = [-1] * N
P[0] = -2
D = [-10] * N
D[0] = 0
Q = collections.deque([0])
UF = UnionFind(N)
while Q:
    x = Q.popleft()
    Gx = list(G[x])
    for y in Gx:
        if P[x] == y:
            continue
        if D[y] == -10:
            D[y] = D[x] + 1
            P[y] = x
            Q += [y]
        else:
            G[x].remove(y)
            if D[x] > D[y]:
                x, y = y, x
            cy1 = [y]
            cy2 = [x]
            for _ in range(D[y] - D[x]):
                cy1 += [P[cy1[-1]]]
            while True:
                cy1 += [P[cy1[-1]]]
                cy2 += [P[cy2[-1]]]
                if cy1[-1] == cy2[-1]:
                    break
            cy = cy1[-2::-1] + cy2
            if len(cy) % 2:
                print(-1)
                exit()
            c1 = cy[0]
            c2 = cy[1]
            for ca, cb in zip(cy[::2], cy[1::2]):
                UF.unite(c1, ca)
                UF.unite(c2, cb)
UF.scan_uf()
print(len(set(UF.dat)))


Fixed submission:
import numpy as np
import sys
from scipy.sparse.csgraph import floyd_warshall, csgraph_from_dense
N = int(sys.stdin.buffer.readline())
S = np.frombuffer(sys.stdin.buffer.read(),
                  dtype='S1').reshape(N, -1)[:, :N].astype(int)
G = csgraph_from_dense(S)
F = floyd_warshall(G).astype(int)
F2 = F % 2
I0 = np.where(F2[0] == 0)
I1 = np.where(F2[0] == 1)
if (S[I0][:, I0] == 0).all() and (S[I1][:, I1] == 0).all():
    print(F.max() + 1)
    exit()
print(-1)

Buggy python submission (verdict: Runtime Error):
import collections, itertools


class UnionFind():
    def __init__(self, size):
        self.dat = list(range(size))
        self.SIZE = [1] * size  # 0-indexed

    def find(self, x):
        dat = self.dat
        stack = [x]
        while True:
            y = stack[-1]
            if dat[y] != y:
                stack += [dat[y]]
            else:
                break
        for s in stack:
            dat[s] = y
        return y

    def unite(self, x, y):
        is_same = self.is_same
        find = self.find
        SIZE = self.SIZE
        dat = self.dat
        if not is_same(x, y):
            X, Y = find(x), find(y)
            SX, SY = SIZE[X], SIZE[Y]
            if SX > SY:
                m = dat[X] = Y
            else:
                m = dat[Y] = X
            SIZE[m] = SX + SY
            SIZE[X + Y - m] = 0

    def is_same(self, x, y):
        find = self.find
        return find(x) == find(y)

    def scan_uf(self):
        find = self.find
        length = len(self.dat)
        for i in range(length):
            find(i)

    def size(self, x):
        return self.SIZE[self.find(x)]


N = int(input())
S = [[int(_) for _ in input()] for _ in range(N)]
G = collections.defaultdict(set)
for i, j in itertools.product(range(N), repeat=2):
    if S[i][j]:
        G[i].add(j)
P = [-1] * N
P[0] = -2
D = [-10] * N
D[0] = 0
Q = collections.deque([0])
UF = UnionFind(N)
while Q:
    x = Q.popleft()
    Gx = list(G[x])
    for y in Gx:
        if P[x] == y:
            continue
        if D[y] == -10:
            D[y] = D[x] + 1
            P[y] = x
            Q += [y]
        else:
            G[x].remove(y)
            if D[x] > D[y]:
                x, y = y, x
            cy1 = [y]
            cy2 = [x]
            for _ in range(D[y] - D[x]):
                cy1 += [P[cy1[-1]]]
            while True:
                cy1 += [P[cy1[-1]]]
                cy2 += [P[cy2[-1]]]
                if cy1[-1] == cy2[-1]:
                    break
            cy = cy1[-2::-1] + cy2
            if len(cy) % 2:
                print(-1)
                exit()
            c1 = cy[0]
            c2 = cy[1]
            for ca, cb in zip(cy[::2], cy[1::2]):
                UF.unite(c1, ca)
                UF.unite(c2, cb)
UF.scan_uf()
print(len(set(UF.dat)))


Fixed submission:
import numpy as np
import sys
from scipy.sparse.csgraph import floyd_warshall, csgraph_from_dense
N = int(sys.stdin.buffer.readline())
S = np.frombuffer(sys.stdin.buffer.read(),
                  dtype='S1').reshape(N, -1)[:, :N].astype(int)
G = csgraph_from_dense(S)
F = floyd_warshall(G).astype(int)
F2 = F % 2
I0 = np.where(F2[0] == 0)
I1 = np.where(F2[0] == 1)
if (S[I0][:, I0] == 0).all() and (S[I1][:, I1] == 0).all():
    print(F.max() + 1)
    exit()
print(-1)