Problem p02902 (C++)

Buggy submission (status: Time Limit Exceeded):
#include <algorithm>
#include <bitset>
#include <cmath>
#include <fstream>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>

#define MOD_BIG 1000000007
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::string;
using ll = long long;
using std::vector;

template <typename T> void ndarray(vector<T> &vec, int len) { vec.resize(len); }
template <typename T, typename... Args>
void ndarray(vector<T> &vec, int len, Args... args) {
  vec.resize(len);
  for (auto &v : vec)
    ndarray(v, args...);
}

//////////////////////////////////////

enum Status {
  Not = 0,
  Now,
  End,
};

template <typename T> struct Edge {
  int to;
  int from;
  T weight;
  Edge(int from, int to, T weight) : from(from), to(to), weight(weight) {}
};

template <typename T, typename D> struct Graph {
  int n;
  vector<vector<Edge<T>>> g;
  vector<D> data;
  vector<Status> s;

  Graph(int N) : n(N), g(N + 1), data(N + 1), s(N + 1) {}

  void add_edge(int from, Edge<T> e) { g[from].push_back(e); }
  void set_data(int node, D value) { data[node] = value; }

  // 幅優先探索による最短経路
  // weightが全て同一の場合線形
  std::pair<vector<T>, vector<vector<Edge<T>>>> bfs_spp(int start) {
    vector<T> d(n + 1, -1);
    vector<vector<Edge<T>>> route(n + 1);
    std::queue<int> q;
    d[start] = 0;
    q.push(start);
    while (!q.empty()) {
      int v = q.front();
      q.pop();

      for (auto e : g[v]) {
        if (d[e.to] != -1 && d[e.to] != 0) {
          // 到達済み
          continue;
        }
        d[e.to] = d[e.from] + 1;
        auto tmp = route[e.from];
        tmp.push_back(e);
        route[e.to] = tmp;
        q.push(e.to);
      }
    }
    return std::make_pair(d, route);
  }

  // ダイクストラ法
  // weightが非負の場合の最短経路
  // 経路が存在しない場合、INFが返るのでオーバーフローに注意
  std::pair<vector<T>, vector<vector<Edge<T>>>> dijkstra(int start) {
    using P = std::pair<T, int>;
    std::priority_queue<P, vector<P>, std::greater<P>> que;
    T T_MAX = std::numeric_limits<T>::max();
    vector<T> d(n + 1, T_MAX);
    vector<vector<Edge<T>>> route(n + 1);
    d[start] = 0;
    que.push(P((T)0, start));
    while (!que.empty()) {
      P p = que.top();
      que.pop();
      int v = p.second;
      if (d[v] < p.first)
        continue;
      for (Edge<T> e : g[v]) {
        if (d[e.to] > d[v] + e.weight || d[e.to] == 0) {
          d[e.to] = d[v] + e.weight;
          auto tmp = route[e.from];
          tmp.push_back(e);
          route[e.to] = tmp;
          que.push(P(d[e.to], e.to));
        }
      }
    }
    return std::make_pair(d, route);
  }

  // ベルマン-フォード法
  // weightを負を含む距離として最短経路を求める
  // 無限ループが存在する場合、trueを1つ目に返す
  std::pair<bool, vector<T>> bellman_ford(int start) {
    T T_INF = std::numeric_limits<T>::max();
    vector<T> d(n + 1, T_INF);
    vector<Edge<T>> E;
    for (int i = 0; i <= n; i++) {
      for (auto e : g[i]) {
        E.push_back(e);
      }
    }
    d[start] = 0;
    for (int i = 0; i <= n; i++) {
      for (auto e : E) {
        if (d[e.from] != T_INF && d[e.from] + e.weight < d[e.to]) {
          // 最初or別のstartからe.toへの最短路を発見
          d[e.to] = d[e.from] + e.weight;
          // std::cout << "new route find, to: " << e.to << ", distance: " <<
          // d[e.to] << std::endl;
          if (i == n) {
            // もう全ての辺はチェック済みのはずなのにまだ更新がある：無限ループあり
            return std::make_pair(true, d);
          }
        }
      }
    }
    return std::make_pair(false, d);
  }

  // あるノードに到達できるか
  // 逆方向はグラフ自体逆で構成することで可能
  vector<bool> can_reach_from(int start) {
    vector<bool> reached(n + 1, false);
    dfs_reach_from(start, reached);
    return reached;
  }
  void dfs_reach_from(int now, vector<bool> &reached) {
    if (reached[now])
      return;
    reached[now] = true;
    for (auto e : g[now]) {
      dfs_reach_from(e.to, reached);
    }
  }

  // 出力
  void print() {
    for (auto v : g) {
      for (auto e : v) {
        std::cout << e.from << "-(" << e.weight << ")->" << e.to << ", ";
      }
      std::cout << std::endl;
    }
  }

  int dfs(int now, int par, int depth);
  std::pair<vector<T>, vector<vector<Edge<T>>>> bfs(int start, ll k);
};

template <typename T, typename D>
int Graph<T, D>::dfs(int now, int par, int depth) {
  // std::cout << "searching now: " << now << std::endl;
  if (g[now].empty()) {
    // 終端ノード
  }
  int res = 0;
  s[now] = Status::Now;
  for (auto e : g[now]) {
    int chi = e.to;
    if (s[chi] == Status::Now) {
      // 閉路あり
    } else if (s[chi] == Status::End) {
      // 探索済み(親が複数) ここを使う場合メモできないか考える
    } else {
      // 未探索
      dfs(chi, now, depth + 1);
    }
  }
  s[now] = Status::End;
  return res;
}

template <typename T, typename D>
std::pair<vector<T>, vector<vector<Edge<T>>>> Graph<T, D>::bfs(int start,
                                                               ll k) {
  vector<T> d(n + 1, -1);
  vector<vector<Edge<T>>> route(n + 1);
  std::queue<int> q;
  d[start] = 0;
  q.push(start);
  while (!q.empty()) {
    int v = q.front();
    if (d[v] > k) {
      // 更新可能性なし
      d[v] = -1;
      return std::make_pair(d, route);
    }
    q.pop();

    for (auto e : g[v]) {
      if (d[e.to] != -1 && e.to != start) {
        // 到達済みがゴールにたどり着く前に出る：このスタートははずれ
        d[v] = -1;
        return std::make_pair(d, route);
      }
      d[e.to] = d[e.from] + 1;
      auto tmp = route[e.from];
      tmp.push_back(e);
      route[e.to] = tmp;
      q.push(e.to);
      if (e.to == start) {
        return std::make_pair(d, route);
      }
    }
  }
  return std::make_pair(d, route);
}

//////////////////////////////////////

int main() {

  int N, M;
  cin >> N >> M;
  Graph<ll, ll> g(N);

  for (int i = 0; i < M; i++) {
    int a, b;
    cin >> a >> b;
    g.add_edge(a, Edge<ll>(a, b, 1));
  }

  ll K = std::numeric_limits<ll>::max();
  vector<Edge<ll>> route;
  vector<bool> checked(N + 1);
  for (int i = 1; i <= N; i++) {
    if (checked[i]) {
      continue;
    }
    auto res = g.bfs(i, K);
    // cerr << res.first[i] << endl;
    if (res.first[i] == 0) {
      // このノードからつながる先にループはない うまくいかない
      for (auto r : res.second) {
        for (auto e : r) {
          // checked[e.to] = true;
        }
      }
    } else if (res.first[i] == -1) {
      continue;
    } else if (K > res.first[i]) {
      K = res.first[i];
      route = res.second[i];
    }
    if (i > N / 2) {
      bool ok = true;
      std::multiset<int> s;
      for (auto e : route) {
        s.insert(e.from);
      }
      for (auto n : s) {
        int cnt = 0;
        for (auto e : g.g[n]) {
          cnt += s.count(e.to);
        }
        if (cnt >= 2) {
          ok = false;
          break;
        }
      }
      if (ok) {
        break;
      }
    }
  }

  if (K == std::numeric_limits<ll>::max()) {
    cout << -1 << endl;
    return 0;
  }
  cout << K << endl;
  for (auto e : route) {
    cout << e.from << endl;
  }

  return 0;
}


Fixed submission:
#include <algorithm>
#include <bitset>
#include <cmath>
#include <fstream>
#include <iostream>
#include <limits>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <unordered_set>
#include <vector>

#define MOD_BIG 1000000007
using std::cerr;
using std::cin;
using std::cout;
using std::endl;
using std::string;
using ll = long long;
using std::vector;

template <typename T> void ndarray(vector<T> &vec, int len) { vec.resize(len); }
template <typename T, typename... Args>
void ndarray(vector<T> &vec, int len, Args... args) {
  vec.resize(len);
  for (auto &v : vec)
    ndarray(v, args...);
}

//////////////////////////////////////

enum Status {
  Not = 0,
  Now,
  End,
};

template <typename T> struct Edge {
  int to;
  int from;
  T weight;
  Edge(int from, int to, T weight) : from(from), to(to), weight(weight) {}
};

template <typename T, typename D> struct Graph {
  int n;
  vector<vector<Edge<T>>> g;
  vector<D> data;
  vector<Status> s;

  Graph(int N) : n(N), g(N + 1), data(N + 1), s(N + 1) {}

  void add_edge(int from, Edge<T> e) { g[from].push_back(e); }
  void set_data(int node, D value) { data[node] = value; }

  // 幅優先探索による最短経路
  // weightが全て同一の場合線形
  std::pair<vector<T>, vector<vector<Edge<T>>>> bfs_spp(int start) {
    vector<T> d(n + 1, -1);
    vector<vector<Edge<T>>> route(n + 1);
    std::queue<int> q;
    d[start] = 0;
    q.push(start);
    while (!q.empty()) {
      int v = q.front();
      q.pop();

      for (auto e : g[v]) {
        if (d[e.to] != -1 && d[e.to] != 0) {
          // 到達済み
          continue;
        }
        d[e.to] = d[e.from] + 1;
        auto tmp = route[e.from];
        tmp.push_back(e);
        route[e.to] = tmp;
        q.push(e.to);
      }
    }
    return std::make_pair(d, route);
  }

  // ダイクストラ法
  // weightが非負の場合の最短経路
  // 経路が存在しない場合、INFが返るのでオーバーフローに注意
  std::pair<vector<T>, vector<vector<Edge<T>>>> dijkstra(int start) {
    using P = std::pair<T, int>;
    std::priority_queue<P, vector<P>, std::greater<P>> que;
    T T_MAX = std::numeric_limits<T>::max();
    vector<T> d(n + 1, T_MAX);
    vector<vector<Edge<T>>> route(n + 1);
    d[start] = 0;
    que.push(P((T)0, start));
    while (!que.empty()) {
      P p = que.top();
      que.pop();
      int v = p.second;
      if (d[v] < p.first)
        continue;
      for (Edge<T> e : g[v]) {
        if (d[e.to] > d[v] + e.weight || d[e.to] == 0) {
          d[e.to] = d[v] + e.weight;
          auto tmp = route[e.from];
          tmp.push_back(e);
          route[e.to] = tmp;
          que.push(P(d[e.to], e.to));
        }
      }
    }
    return std::make_pair(d, route);
  }

  // ベルマン-フォード法
  // weightを負を含む距離として最短経路を求める
  // 無限ループが存在する場合、trueを1つ目に返す
  std::pair<bool, vector<T>> bellman_ford(int start) {
    T T_INF = std::numeric_limits<T>::max();
    vector<T> d(n + 1, T_INF);
    vector<Edge<T>> E;
    for (int i = 0; i <= n; i++) {
      for (auto e : g[i]) {
        E.push_back(e);
      }
    }
    d[start] = 0;
    for (int i = 0; i <= n; i++) {
      for (auto e : E) {
        if (d[e.from] != T_INF && d[e.from] + e.weight < d[e.to]) {
          // 最初or別のstartからe.toへの最短路を発見
          d[e.to] = d[e.from] + e.weight;
          // std::cout << "new route find, to: " << e.to << ", distance: " <<
          // d[e.to] << std::endl;
          if (i == n) {
            // もう全ての辺はチェック済みのはずなのにまだ更新がある：無限ループあり
            return std::make_pair(true, d);
          }
        }
      }
    }
    return std::make_pair(false, d);
  }

  // あるノードに到達できるか
  // 逆方向はグラフ自体逆で構成することで可能
  vector<bool> can_reach_from(int start) {
    vector<bool> reached(n + 1, false);
    dfs_reach_from(start, reached);
    return reached;
  }
  void dfs_reach_from(int now, vector<bool> &reached) {
    if (reached[now])
      return;
    reached[now] = true;
    for (auto e : g[now]) {
      dfs_reach_from(e.to, reached);
    }
  }

  // 出力
  void print() {
    for (auto v : g) {
      for (auto e : v) {
        std::cout << e.from << "-(" << e.weight << ")->" << e.to << ", ";
      }
      std::cout << std::endl;
    }
  }

  int dfs(int now, int par, int depth);
  std::pair<vector<T>, vector<vector<Edge<T>>>> bfs(int start, ll k);
};

template <typename T, typename D>
int Graph<T, D>::dfs(int now, int par, int depth) {
  // std::cout << "searching now: " << now << std::endl;
  if (g[now].empty()) {
    // 終端ノード
  }
  int res = 0;
  s[now] = Status::Now;
  for (auto e : g[now]) {
    int chi = e.to;
    if (s[chi] == Status::Now) {
      // 閉路あり
    } else if (s[chi] == Status::End) {
      // 探索済み(親が複数) ここを使う場合メモできないか考える
    } else {
      // 未探索
      dfs(chi, now, depth + 1);
    }
  }
  s[now] = Status::End;
  return res;
}

template <typename T, typename D>
std::pair<vector<T>, vector<vector<Edge<T>>>> Graph<T, D>::bfs(int start,
                                                               ll k) {
  vector<T> d(n + 1, -1);
  vector<vector<Edge<T>>> route(n + 1);
  std::queue<int> q;
  d[start] = 0;
  q.push(start);
  while (!q.empty()) {
    int v = q.front();
    if (d[v] > k) {
      // 更新可能性なし
      d[v] = -1;
      return std::make_pair(d, route);
    }
    q.pop();

    for (auto e : g[v]) {
      if (d[e.to] != -1 && e.to != start) {
        // 到達済みがゴールにたどり着く前に出る：このスタートははずれ
        d[v] = -1;
        return std::make_pair(d, route);
      }
      d[e.to] = d[e.from] + 1;
      auto tmp = route[e.from];
      tmp.push_back(e);
      route[e.to] = tmp;
      q.push(e.to);
      if (e.to == start) {
        return std::make_pair(d, route);
      }
    }
  }
  return std::make_pair(d, route);
}

//////////////////////////////////////

int main() {

  int N, M;
  cin >> N >> M;
  Graph<ll, ll> g(N);

  for (int i = 0; i < M; i++) {
    int a, b;
    cin >> a >> b;
    g.add_edge(a, Edge<ll>(a, b, 1));
  }

  ll K = std::numeric_limits<ll>::max();
  vector<Edge<ll>> route;
  vector<bool> checked(N + 1);
  for (int i = 1; i <= N; i++) {
    if (checked[i]) {
      continue;
    }
    auto res = g.bfs(i, K);
    // cerr << res.first[i] << endl;
    if (res.first[i] == 0) {
      // このノードからつながる先にループはない うまくいかない
      for (auto r : res.second) {
        for (auto e : r) {
          // checked[e.to] = true;
        }
      }
    } else if (res.first[i] == -1) {
      continue;
    } else if (K > res.first[i]) {
      K = res.first[i];
      route = res.second[i];
    }
    if (route.size() > 2) {
      bool ok = true;
      std::multiset<int> s;
      for (auto e : route) {
        s.insert(e.from);
      }
      for (auto n : s) {
        int cnt = 0;
        for (auto e : g.g[n]) {
          cnt += s.count(e.to);
        }
        if (cnt >= 2) {
          ok = false;
          break;
        }
      }
      if (ok) {
        break;
      }
    }
  }

  if (K == std::numeric_limits<ll>::max()) {
    cout << -1 << endl;
    return 0;
  }
  cout << K << endl;
  for (auto e : route) {
    cout << e.from << endl;
  }

  return 0;
}