Problem p02892 (C++)

Buggy submission (status: Runtime Error):
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T> T mpow(T a, T n) {
  T res = 1;
  for (; n; n >>= 1) {
    if (n & 1)
      res = res * a;
    a = a * a;
  }
  return res;
}
vector<string> v(200);

template <typename T> class UnionFind {
public:
  // 以下公開

  // 親の番号を格納する。親である場合は-(その集合のサイズ)
  vector<T> Parent;

  // 作るときはParentの値を全て-1にする
  // こうすると全てバラバラになる
  UnionFind(T N) { Parent = vector<T>(N, -1); }

  // Aがどのグループに属しているか調べる
  T root(T A) {
    if (Parent[A] < 0)
      return A;
    return Parent[A] = root(Parent[A]);
  } // 代入しておくことで参照を速くする

  // 自分のいるグループの頂点数を調べる
  T size(T A) {
    return -Parent[root(A)];
  } // 親である場合は-(その集合のサイズ)なので、Ａの親の

  // AとBをくっ付ける
  bool connect(T A, T B) {
    // AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
    A = root(A);
    B = root(B);
    if (A == B) {
      // すでにくっついてるからくっ付けない
      return false;
    }

    // 大きい方(A)に小さいほう(B)をくっ付けたい
    // 大小が逆だったらひっくり返しちゃう。
    if (size(A) < size(B))
      swap(A, B);

    // Aのサイズを更新する
    Parent[A] += Parent[B];
    // Bの親をAに変更する
    Parent[B] = A;

    return true;
  }

  bool same(T A, T B) { return root(A) == root(B); }
};

ll dp[110][110] = {};

signed main() {
  ll n, ans = -1;
  cin >> n;
  UnionFind<ll> u(2 * n);

  rep(i, 0, n) {
    cin >> v[i];
    rep(j, 0, n) {
      if (v[i][j] == '1') {
        u.connect(i, j + n);
        u.connect(i + n, j);
        dp[i][j] = 1;
      } else {
        if (i != j)
          dp[i][j] = INF;
      }
    }
  }

  rep(i, 0, n) {
    if (u.same(i, i + n)) {
      cout << -1 << endl;
      return 0;
    }
  }

  rep(k, 0, n) rep(i, 0, n) rep(j, 0, n) {
    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
  }

  rep(i, 0, n) rep(j, 0, n) { ans = max(ans, dp[i][j]); }

  cout << ans + 1 << endl;
}

Fixed submission:
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using db = double;
using ld = long double;
#define fs first
#define sc second
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define eb emplace_back
#define all(v) (v).begin(), (v).end()
#define siz(v) (ll)(v).size()
#define rep(i, a, n) for (ll i = a; i < (ll)(n); i++)
#define repr(i, a, n) for (ll i = n - 1; (ll)a <= i; i--)
#define lb lower_bound
#define ub upper_bound
typedef pair<int, int> P;
typedef pair<ll, ll> PL;
const ll mod = 1000000007;
const ll INF = 1000000099;
const ll LINF = (ll)(1e18 + 99);
vector<ll> dx = {-1, 1, 0, 0}, dy = {0, 0, -1, 1};
template <typename T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template <typename T> T mpow(T a, T n) {
  T res = 1;
  for (; n; n >>= 1) {
    if (n & 1)
      res = res * a;
    a = a * a;
  }
  return res;
}
vector<string> v(200);

template <typename T> class UnionFind {
public:
  // 以下公開

  // 親の番号を格納する。親である場合は-(その集合のサイズ)
  vector<T> Parent;

  // 作るときはParentの値を全て-1にする
  // こうすると全てバラバラになる
  UnionFind(T N) { Parent = vector<T>(N, -1); }

  // Aがどのグループに属しているか調べる
  T root(T A) {
    if (Parent[A] < 0)
      return A;
    return Parent[A] = root(Parent[A]);
  } // 代入しておくことで参照を速くする

  // 自分のいるグループの頂点数を調べる
  T size(T A) {
    return -Parent[root(A)];
  } // 親である場合は-(その集合のサイズ)なので、Ａの親の

  // AとBをくっ付ける
  bool connect(T A, T B) {
    // AとBを直接つなぐのではなく、root(A)にroot(B)をくっつける
    A = root(A);
    B = root(B);
    if (A == B) {
      // すでにくっついてるからくっ付けない
      return false;
    }

    // 大きい方(A)に小さいほう(B)をくっ付けたい
    // 大小が逆だったらひっくり返しちゃう。
    if (size(A) < size(B))
      swap(A, B);

    // Aのサイズを更新する
    Parent[A] += Parent[B];
    // Bの親をAに変更する
    Parent[B] = A;

    return true;
  }

  bool same(T A, T B) { return root(A) == root(B); }
};

ll dp[210][210] = {};

signed main() {
  ll n, ans = -1;
  cin >> n;
  UnionFind<ll> u(2 * n);

  rep(i, 0, n) {
    cin >> v[i];
    rep(j, 0, n) {
      if (v[i][j] == '1') {
        u.connect(i, j + n);
        u.connect(i + n, j);
        dp[i][j] = 1;
      } else {
        if (i != j)
          dp[i][j] = INF;
      }
    }
  }

  rep(i, 0, n) {
    if (u.same(i, i + n)) {
      cout << -1 << endl;
      return 0;
    }
  }

  rep(k, 0, n) rep(i, 0, n) rep(j, 0, n) {
    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k][j]);
  }

  rep(i, 0, n) rep(j, 0, n) { ans = max(ans, dp[i][j]); }

  cout << ans + 1 << endl;
}