Problem:
L - Flipping a Path
問題文
$N$ 頂点 $M$ 辺の単純有向グラフが与えられます。​
このグラフの頂点には $1$ から $N$ までの番号がついていて、辺には $1$ から $M$ までの番号がついています。​
辺 $i$ $(1 \le i \le M)$ は、頂点 $u_i$ から頂点 $v_i$ へ向かう辺です。​
次の条件を満たす辺素パスが存在するか判定し、存在する場合はそのようなパスの長さの最小値を求めてください。​
パスに含まれるすべての辺の向きを逆にすると、グラフ全体が強連結になる。​
ここで長さ $K$ $(K \ge 0)$ の辺素パスとは、次の条件を満たす辺の番号の列 $(e_1, e_2, \ldots, e_K)$ のことです。​
$1 \le i \le K-1$ について $v_{e_i} = u_{e_{i+1}}$ である。
どのような $1 \le i < j \le K$ についても、$e_i \ne e_j$ である。​
特にこの問題では、長さ $K$ が $0$ となるものも辺素パスとして認めることにします。
また、「グラフが強連結である」とは、「そのグラフのどのような $2$ 頂点 $s, t$ $(s \ne t)$ についても、$s$ から $t$ への辺素パス、つまり、$u_{e_0} = s$ かつ $v_{e_K} = t$ を満たす辺素パスが存在する」ということです。
入力
入力は以下の形式で標準入力から与えられる。
$N$ $M$
$u_1$ $v_1$
$u_2$ $v_2$
$\vdots$
$u_M$ $v_M$
制約
$2 \le N \le 10^5$
$1 \le M \le \min (10^5, N(N-1))$
$1 \le u_i \le N$
$1 \le v_i \le N$
$u_i \ne v_i$
どのような $(i, j)$ $(1 \le i < j \le M)$ についても、$(u_i, v_i) \ne (u_j, v_j)$
出力
条件を満たす辺素パスが存在しない場合は
-1
を出力せよ。
そうでない場合は、条件を満たすパスの長さの最小値を出力せよ。
入力例 1
4 5
1 2
1 3
2 3
2 4
3 4
出力例 1
2
与えられるグラフは次のようになります。
例えば長さ $2$ の辺素パス $(e_1, e_2) = (2, 5)$ を逆にすると、次の図のようにグラフ全体を強連結にすることができます。
$1$ 本の辺を逆にしても強連結にはできないので、条件を満たすパスの長さの最小値は $2$ となります。
入力例 2
4 5
1 2
3 1
2 3
2 4
4 3
出力例 2
0
与えられるグラフは次のようになります。
グラフはすでに強連結なので、辺を逆にする必要がありません。
入力例 3
2 1
1 2
出力例 3
-1
辺を逆にしてもしなくても、グラフは強連結になりません。

Submitted solutions:

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<long double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

struct SCC{
    vector<vector<int> > gg,rg;
    vector<int> comp,order;
    vector<bool> used;
    vector<vector<int> > ng,vs;
    int n,nn;
    SCC(){}
    SCC(int v):gg(v),rg(v),comp(v,-1),used(v,0),n(v){}
    void add_edge(int x,int y){
        gg[x].push_back(y);
        rg[y].push_back(x);
    }
    void dfs(int v){
        used[v]=1;
        for(int i:gg[v]){
            if(!used[i])dfs(i);
        }
        order.push_back(v);
    }
    void rdfs(int v,int k){
        used[v]=1;
        comp[v]=k;
        for(int i:rg[v]){
            if(!used[i])rdfs(i,k);
        }
    }
    int build(){
        for(int i=0;i<n;i++){
            if(!used[i])dfs(i);
        }
        for(int i=0;i<n;i++){
            used[i]=0;
        }
        int k=0;
        for(int i=order.size()-1;i>=0;i--){
            if(!used[order[i]])rdfs(order[i],k++);
        }
        nn=k;
        // それぞれの強連結成分に含まれる頂点の番号
        vs.resize(k,vector<int>());
        for(int i=0;i<n;i++){
            vs[comp[i]].push_back(i);
        }
        // 強連結成分をまとめた後のグラフ
        ng.resize(k,vector<int>());
        for(int i=0;i<n;i++){
            for(int j:gg[i]){
                if(comp[i]!=comp[j]){
                    ng[comp[i]].push_back(comp[j]);
                }
            }
        }
        for(int i=0;i<nn;i++){
            sort(ng[i].begin(),ng[i].end());
            ng[i].erase(unique(ng[i].begin(),ng[i].end()),ng[i].end());
        }
        return k;
    }
};

template<typename T>
struct dinic{
    struct edge{
        int to;
        T c,f;
    };
    T eps;
    const T inf=numeric_limits<T>::max();
    int n,m = 0;
    vector<edge> e;
    vector<vector<int>> g;
    vector<int> level, ptr;
    dinic(int n): n(n), g(n), level(n), ptr(n) {
        eps = (T)1 / (T)1e9;
    }
    void add_edge(int s, int t, T c){
        e.push_back({t, c, 0});
        e.push_back({s, 0, 0});
        g[s].push_back(m++);
        g[t].push_back(m++);
    }
    bool bfs(int s, int t){
        fill(level.begin(), level.end(), -1);
        level[s] = 0;
        for(queue<int> q({s});q.size();q.pop()){
            int s = q.front();
            for(int i:g[s]){
                int t = e[i].to;
                if(level[t] == -1 and (e[i].c - e[i].f) > eps){
                    level[t] = level[s] + 1;
                    q.push(t);
                }
            }
        }
        return (level[t] != -1);
    }
    T dfs(int s, int t, T psh){
        if(!(psh > eps) or s == t) return psh;
        for(int &i = ptr[s]; i < (int)g[s].size(); ++i){
            auto &eg = e[g[s][i]];
            if(level[eg.to] != level[s] + 1 or !(eg.c - eg.f > eps)) continue;
            T f = dfs(eg.to, t, min(psh, eg.c-eg.f));
            if(f > eps){
                eg.f += f;
                e[g[s][i]^1].f -= f;
                return f;
            }
        }
        return 0;
    }
    T max_flow(int s, int t){
        T f = 0;
        while(bfs(s,t)){
            fill(ptr.begin(), ptr.end(), 0);
            while(1){
                T c = dfs(s, t, inf);
                if(c > eps){
                    f += c;
                }
                else{
                    break;
                }
            }
        }
        return f;
    }
    // ABC239-G
    vector<bool> min_cut(int s){
        vector<bool> visited(n);
        queue<int> q; q.push(s);
        while(q.size()){
            int p = q.front(); q.pop();
            visited[p] = true;
            for(auto idx:g[p]){
                auto eg = e[idx];
                if(eg.c - eg.f > eps and !visited[eg.to]){
                    visited[eg.to] = true;
                    q.push(eg.to);
                }
            }
        }
        return visited;
    }
};

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n,m; cin >> n >> m;
    SCC G(n);
    for (int i = 0; i < m; ++i) {
        int x,y; cin >> x >> y;
        x--; y--;
        G.add_edge(x, y);
    }
    int sz = G.build();
    if (sz == 1) {
        cout << 0 << endl;
        return 0;
    }
    auto ng = G.ng;
    int s = -1, t = -1;
    {
        vector<int> deg(sz);
        for (int i = 0; i < sz; ++i) {
            for (int j : ng[i]) {
                deg[j]++;
            }
        }
        for (int i = 0; i < sz; ++i) {
            if (deg[i] == 0) {
                if (s == -1) s = i;
                else {
                    cout << -1 << endl;
                    return 0;
                }
            }
        }
        for (int i = 0; i < sz; ++i) {
            if (ng[i].size() == 0) {
                if (t == -1) t = i;
                else {
                    cout << -1 << endl;
                    return 0;
                }
            }
        }
    }
    vector<vector<int>> g(n+2);
    dinic<int> dc(n+2);
    for (int i = 0; i < n; ++i) {
        int u = (G.comp[i] == s ? n : i);
        for (int j : G.gg[i]) {
            int v = (G.comp[j] == t ? n+1 : j);
            g[u].push_back(v);
            dc.add_edge(u, v, 1);
        }
    }
    if (dc.max_flow(n, n+1) == 1) {
        cout << -1 << endl;
        return 0;
    }
    vector<int> d(n+2, -1);
    queue<int> q;
    q.push(n); d[n] = 0;
    while (q.size()) {
        int p = q.front(); q.pop();
        for (int pp : g[p]) {
            if (d[pp] == -1) {
                d[pp] = d[p] + 1;
                q.push(pp);
            }
        }
    }
    cout << d[n+1] << endl;
}
accuracy: 1
time_ms: 80
memory_kb: 49784
final_rank: 7

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<long double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

struct SCC{
    vector<vector<int> > gg,rg;
    vector<int> comp,order;
    vector<bool> used;
    vector<vector<int> > ng,vs;
    int n,nn;
    SCC(){}
    SCC(int v):gg(v),rg(v),comp(v,-1),used(v,0),n(v){}
    void add_edge(int x,int y){
        gg[x].push_back(y);
        rg[y].push_back(x);
    }
    void dfs(int v){
        used[v]=1;
        for(int i:gg[v]){
            if(!used[i])dfs(i);
        }
        order.push_back(v);
    }
    void rdfs(int v,int k){
        used[v]=1;
        comp[v]=k;
        for(int i:rg[v]){
            if(!used[i])rdfs(i,k);
        }
    }
    int build(){
        for(int i=0;i<n;i++){
            if(!used[i])dfs(i);
        }
        for(int i=0;i<n;i++){
            used[i]=0;
        }
        int k=0;
        for(int i=order.size()-1;i>=0;i--){
            if(!used[order[i]])rdfs(order[i],k++);
        }
        nn=k;
        // それぞれの強連結成分に含まれる頂点の番号
        vs.resize(k,vector<int>());
        for(int i=0;i<n;i++){
            vs[comp[i]].push_back(i);
        }
        // 強連結成分をまとめた後のグラフ
        ng.resize(k,vector<int>());
        for(int i=0;i<n;i++){
            for(int j:gg[i]){
                if(comp[i]!=comp[j]){
                    ng[comp[i]].push_back(comp[j]);
                }
            }
        }
        for(int i=0;i<nn;i++){
            sort(ng[i].begin(),ng[i].end());
            ng[i].erase(unique(ng[i].begin(),ng[i].end()),ng[i].end());
        }
        return k;
    }
};

template<typename T>
struct dinic{
    struct edge{
        int to;
        T c,f;
    };
    T eps;
    const T inf=numeric_limits<T>::max();
    int n,m = 0;
    vector<edge> e;
    vector<vector<int>> g;
    vector<int> level, ptr;
    dinic(int n): n(n), g(n), level(n), ptr(n) {
        eps = (T)1 / (T)1e9;
    }
    void add_edge(int s, int t, T c){
        e.push_back({t, c, 0});
        e.push_back({s, 0, 0});
        g[s].push_back(m++);
        g[t].push_back(m++);
    }
    bool bfs(int s, int t){
        fill(level.begin(), level.end(), -1);
        level[s] = 0;
        for(queue<int> q({s});q.size();q.pop()){
            int s = q.front();
            for(int i:g[s]){
                int t = e[i].to;
                if(level[t] == -1 and (e[i].c - e[i].f) > eps){
                    level[t] = level[s] + 1;
                    q.push(t);
                }
            }
        }
        return (level[t] != -1);
    }
    T dfs(int s, int t, T psh){
        if(!(psh > eps) or s == t) return psh;
        for(int &i = ptr[s]; i < (int)g[s].size(); ++i){
            auto &eg = e[g[s][i]];
            if(level[eg.to] != level[s] + 1 or !(eg.c - eg.f > eps)) continue;
            T f = dfs(eg.to, t, min(psh, eg.c-eg.f));
            if(f > eps){
                eg.f += f;
                e[g[s][i]^1].f -= f;
                return f;
            }
        }
        return 0;
    }
    T max_flow(int s, int t){
        T f = 0;
        while(bfs(s,t)){
            fill(ptr.begin(), ptr.end(), 0);
            while(1){
                T c = dfs(s, t, inf);
                if(c > eps){
                    f += c;
                }
                else{
                    break;
                }
            }
        }
        return f;
    }
    // ABC239-G
    vector<bool> min_cut(int s){
        vector<bool> visited(n);
        queue<int> q; q.push(s);
        while(q.size()){
            int p = q.front(); q.pop();
            visited[p] = true;
            for(auto idx:g[p]){
                auto eg = e[idx];
                if(eg.c - eg.f > eps and !visited[eg.to]){
                    visited[eg.to] = true;
                    q.push(eg.to);
                }
            }
        }
        return visited;
    }
};

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n,m; cin >> n >> m;
    SCC G(n);
    for (int i = 0; i < m; ++i) {
        int x,y; cin >> x >> y;
        x--; y--;
        G.add_edge(x, y);
    }
    int sz = G.build();
    if (sz == 1) {
        cout << 0 << endl;
        return 0;
    }
    auto ng = G.ng;
    int s = -1, t = -1;
    {
        vector<int> deg(sz);
        for (int i = 0; i < sz; ++i) {
            for (int j : ng[i]) {
                deg[j]++;
            }
        }
        for (int i = 0; i < sz; ++i) {
            if (deg[i] == 0) {
                if (s == -1) s = i;
                else {
                    cout << -1 << endl;
                    return 0;
                }
            }
        }
        for (int i = 0; i < sz; ++i) {
            if (ng[i].size() == 0) {
                if (t == -1) t = i;
                else {
                    cout << -1 << endl;
                    return 0;
                }
            }
        }
    }
    vector<vector<int>> g(n+2);
    dinic<int> dc(n+2);
    for (int i = 0; i < n; ++i) {
        int u = (i == s ? n : i);
        for (int j : G.gg[i]) {
            int v = (j == t ? n+1 : j);
            g[u].push_back(v);
            dc.add_edge(u, v, 1);
        }
    }
    if (dc.max_flow(n, n+1) == 1) {
        cout << -1 << endl;
        return 0;
    }
    vector<int> d(n+2, -1);
    queue<int> q;
    q.push(n); d[n] = 0;
    while (q.size()) {
        int p = q.front(); q.pop();
        for (int pp : g[p]) {
            if (d[pp] == -1) {
                d[pp] = d[p] + 1;
                q.push(pp);
            }
        }
    }
    cout << d[n+1] << endl;
}
accuracy: 0.3783783783783784
time_ms: 30
memory_kb: 21464
final_rank: 16

code_snippet: // verification-helper: PROBLEM http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=3183

#include<bits/stdc++.h>
using namespace std;

#define call_from_test
#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T> void drop(const T &x){cout<<x<<endl;exit(0);}
//END CUT HERE
#ifndef call_from_test
//INSERT ABOVE HERE
signed main(){
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
struct SCC{
  vector< vector<int> > G,R,H,C;
  vector<int> vs,used,blg;
  SCC(){}
  SCC(int n):G(n),R(n),used(n),blg(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    R[v].emplace_back(u);
  }

  void dfs(int v){
    used[v]=1;
    for(int u:G[v])
      if(!used[u]) dfs(u);
    vs.emplace_back(v);
  }

  void rdfs(int v,int k){
    used[v]=1;
    blg[v]=k;
    C[k].emplace_back(v);
    for(int u:R[v])
      if(!used[u]) rdfs(u,k);
  }

  int build(bool uniq=true){
    int n=G.size();
    for(int v=0;v<n;v++)
      if(!used[v]) dfs(v);

    fill(used.begin(),used.end(),0);
    int k=0;
    for(int i=n-1;i>=0;i--){
      if(!used[vs[i]]){
        H.emplace_back();
        C.emplace_back();
        rdfs(vs[i],k++);
      }
    }

    for(int v=0;v<n;v++)
      for(int u:G[v])
        if(blg[v]!=blg[u])
          H[blg[v]].push_back(blg[u]);

    if(uniq){
      for(int i=0;i<k;i++){
        sort(H[i].begin(),H[i].end());
        H[i].erase(unique(H[i].begin(),H[i].end()),H[i].end());
      }
    }
    return k;
  }

  int operator[](int k) const{return blg[k];}
};
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#ifndef call_from_test
#include <bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
template<typename T>
struct Dijkstra{
  struct Edge{
    int to;
    T cost;
    Edge(int to,T cost):to(to),cost(cost){}
    bool operator<(const Edge &o)const{return cost>o.cost;}
  };

  vector< vector<Edge> > G;
  vector<T> ds;
  vector<int> bs;
  Dijkstra(int n):G(n){}

  void add_edge(int u,int v,T c){
    G[u].emplace_back(v,c);
  }

  void build(int s){
    int n=G.size();
    ds.assign(n,numeric_limits<T>::max());
    bs.assign(n,-1);

    priority_queue<Edge> pq;
    ds[s]=0;
    pq.emplace(s,ds[s]);

    while(!pq.empty()){
      auto p=pq.top();pq.pop();
      int v=p.to;
      if(ds[v]<p.cost) continue;
      for(auto e:G[v]){
        if(ds[e.to]>ds[v]+e.cost){
          ds[e.to]=ds[v]+e.cost;
          bs[e.to]=v;
          pq.emplace(e.to,ds[e.to]);
        }
      }
    }
  }

  T operator[](int k){return ds[k];}

  vector<int> restore(int to){
    vector<int> res;
    if(bs[to]<0) return res;
    while(~to) res.emplace_back(to),to=bs[to];
    reverse(res.begin(),res.end());
    return res;
  }
};
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#ifndef call_from_test
#include<bits/stdc++.h>
using namespace std;
#endif
//BEGIN CUT HERE
// O(F E \log V)
template<typename Flow, bool directed>
struct FordFulkerson{
  struct edge{
    int dst;
    Flow cap;
    int rev;
    edge(){}
    edge(int dst,Flow cap,int rev):dst(dst),cap(cap),rev(rev){}
  };

  vector< vector<edge> > G;
  vector<int> used;

  FordFulkerson(){}
  FordFulkerson(int n):G(n),used(n){}

  int add_edge(int src,int dst,Flow cap){
    int e=G[src].size();
    int r=(src==dst?e+1:G[dst].size());
    G[src].emplace_back(dst,cap,r);
    G[dst].emplace_back(src,directed?0:cap,e);
    return e;
  }

  Flow dfs(int v,int t,Flow f){
    if(v==t) return f;
    used[v]=true;
    for(int i=0;i<(int)G[v].size();i++){
      edge &e=G[v][i];
      if(!used[e.dst]&&e.cap>0){
        Flow d=dfs(e.dst,t,min(f,e.cap));
        if(d==0) continue;
        e.cap-=d;
        G[e.dst][e.rev].cap+=d;
        return d;
      }
    }
    return 0;
  }

  Flow flow(int s,int t,Flow lim){
    Flow fl=0;
    while(1){
      fill(used.begin(),used.end(),0);
      Flow f=dfs(s,t,lim);
      if(f==0) break;
      fl+=f;
      lim-=f;
    }
    return fl;
  }

  Flow flow(int s,int t){
    return flow(s,t,numeric_limits<Flow>::max()/2);
  }
};
//END CUT HERE
#ifndef call_from_test
signed main(){
  return 0;
}
#endif

#undef call_from_test

const int MAX = 303;
int G[MAX][MAX]={};

signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n,m;
  cin>>n>>m;
  SCC G(n);

  int S=n,T=n+1;
  Dijkstra<int> D(n+2);
  FordFulkerson<int, true> F(n+2);
  for(int i=0;i<m;i++){
    int u,v;
    cin>>u>>v;
    u--;v--;
    G.add_edge(u,v);
    D.add_edge(u,v,1);
    F.add_edge(u,v,1);
  }
  int k=G.build();

  vector<int> indeg(n,0);
  vector<int> outdeg(n,0);

  for(int i=0;i<k;i++)
    for(int j:G.H[i])
      outdeg[i]++,indeg[j]++;

  for(int i=0;i<k;i++){
    if(i!=0 and indeg[i]==0) drop(-1);
    if(i!=k-1 and outdeg[i]==0) drop(-1);
  }

  for(int i=0;i<n;i++){
    if(G.blg[i]==0){
      D.add_edge(S,i,0);
      F.add_edge(S,i,2);
    }
    if(G.blg[i]==k-1){
      D.add_edge(i,T,0);
      F.add_edge(i,T,2);
    }
  }

  int res=F.flow(S,T,2);
  if(res!=2) drop(-1);

  D.build(S);
  if(~D.bs[T]) drop(D[T]);
  drop(-1);
  return 0;
}
accuracy: 1
time_ms: 90
memory_kb: 47928
final_rank: 8

code_snippet: #include <bits/stdc++.h>
using namespace std;

using Int = long long;
const char newl = '\n';

template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}
template<typename T> void drop(const T &x){cout<<x<<endl;exit(0);}
template<typename T=int>
vector<T> read(size_t n){
  vector<T> ts(n);
  for(size_t i=0;i<n;i++) cin>>ts[i];
  return ts;
}


struct SCC{
  vector< vector<int> > G,R,T,C;
  vector<int> vs,used,blg;
  SCC(){}
  SCC(int n):G(n),R(n),used(n),blg(n){}

  void add_edge(int u,int v){
    G[u].emplace_back(v);
    R[v].emplace_back(u);
  }

  void dfs(int v){
    used[v]=1;
    for(int u:G[v])
      if(!used[u]) dfs(u);
    vs.emplace_back(v);
  }

  void rdfs(int v,int k){
    used[v]=1;
    blg[v]=k;
    C[k].emplace_back(v);
    for(int u:R[v])
      if(!used[u]) rdfs(u,k);
  }

  int build(){
    int n=G.size();
    for(int v=0;v<n;v++)
      if(!used[v]) dfs(v);

    fill(used.begin(),used.end(),0);
    int k=0;
    for(int i=n-1;i>=0;i--){
      if(!used[vs[i]]){
        T.emplace_back();
        C.emplace_back();
        rdfs(vs[i],k++);
      }
    }

    for(int v=0;v<n;v++)
      for(int u:G[v])
        if(blg[v]!=blg[u])
          T[blg[v]].push_back(blg[u]);
/*
  for(int i=0;i<k;i++){
  sort(T[i].begin(),T[i].end());
  T[i].erase(unique(T[i].begin(),T[i].end()),T[i].end());
  }
*/
    return k;
  }

  int operator[](int k) const{return blg[k];}
};


template<typename T,bool directed>
struct FordFulkerson{
  struct edge{
    int to;
    T cap;
    int rev;
    edge(){}
    edge(int to,T cap,int rev):to(to),cap(cap),rev(rev){}
  };

  vector< vector<edge> > G;
  vector<int> used;

  FordFulkerson(){}
  FordFulkerson(int n):G(n),used(n){}

  void add_edge(int from,int to,T cap){
    G[from].emplace_back(to,cap,G[to].size());
    G[to].emplace_back(from,directed?0:cap,G[from].size()-1);
  }

  T dfs(int v,int t,T f){
    if(v==t) return f;
    used[v]=true;
    for(int i=0;i<(int)G[v].size();i++){
      edge &e=G[v][i];
      if(!used[e.to]&&e.cap>0){
        T d=dfs(e.to,t,min(f,e.cap));
        if(d==0) continue;
        e.cap-=d;
        G[e.to][e.rev].cap+=d;
        return d;
      }
    }
    return 0;
  }

  T flow(int s,int t,T lim){
    T fl=0;
    while(1){
      fill(used.begin(),used.end(),0);
      T f=dfs(s,t,lim);
      if(f==0) break;
      fl+=f;
      lim-=f;
    }
    return fl;
  }

  T flow(int s,int t){
    return flow(s,t,numeric_limits<T>::max()/2);
  }
};


template<typename T>
struct Dijkstra{
  struct Edge{
    int to;
    T cost;
    Edge(int to,T cost):to(to),cost(cost){}
    bool operator<(const Edge &o)const{return cost>o.cost;}
  };

  vector< vector<Edge> > G;
  vector<T> ds;
  vector<int> bs;
  Dijkstra(int n):G(n){}

  void add_edge(int u,int v,T c){
    G[u].emplace_back(v,c);
  }

  void build(int s){
    int n=G.size();
    ds.assign(n,numeric_limits<T>::max());
    bs.assign(n,-1);

    priority_queue<Edge> pq;
    ds[s]=0;
    pq.emplace(s,ds[s]);

    while(!pq.empty()){
      auto p=pq.top();pq.pop();
      int v=p.to;
      if(ds[v]<p.cost) continue;
      for(auto e:G[v]){
        if(ds[e.to]>ds[v]+e.cost){
          ds[e.to]=ds[v]+e.cost;
          bs[e.to]=v;
          pq.emplace(e.to,ds[e.to]);
        }
      }
    }
  }

  T operator[](int k){return ds[k];}

  vector<int> restore(int to){
    vector<int> res;
    if(bs[to]<0) return res;
    while(~to) res.emplace_back(to),to=bs[to];
    reverse(res.begin(),res.end());
    return res;
  }
};

//INSERT ABOVE HERE
signed main(){
  cin.tie(0);
  ios::sync_with_stdio(0);

  int n,m;
  cin>>n>>m;
  SCC G(n);

  int S=n,T=n+1;
  Dijkstra<int> D(n+2);
  FordFulkerson<int, true> F(n+2);
  for(int i=0;i<m;i++){
    int u,v;
    cin>>u>>v;
    u--;v--;
    G.add_edge(u,v);
    D.add_edge(u,v,1);
    F.add_edge(u,v,1);
  }
  int k=G.build();

  vector<int> indeg(n,0);
  vector<int> outdeg(n,0);

  for(int i=0;i<k;i++)
    for(int j:G.T[i])
      outdeg[i]++,indeg[j]++;

  for(int i=0;i<k;i++){
    if(i!=0 and indeg[i]==0) drop(-1);
    if(i!=k-1 and outdeg[i]==0) drop(-1);
  }

  for(int i=0;i<n;i++){
    if(G.blg[i]==0){
      D.add_edge(S,i,0);
      F.add_edge(S,i,2);
    }
    if(G.blg[i]==k-1){
      D.add_edge(i,T,0);
      F.add_edge(i,T,2);
    }
  }

  int res=F.flow(S,T,2);
  // cout<<res<<endl;
  if(res!=2) drop(-1);

  D.build(S);
  if(~D.bs[T]) drop(D[T]);
  drop(-1);
  return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 47256
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;

#define fi first
#define se second
#define repl(i,a,b) for(ll i=(ll)(a);i<(ll)(b);i++)
#define rep(i,n) repl(i,0,n)
#define all(x) (x).begin(),(x).end()
#define dbg(x) cout<<#x"="<<x<<endl
#define mmax(x,y) (x>y?x:y)
#define mmin(x,y) (x<y?x:y)
#define maxch(x,y) x=mmax(x,y)
#define minch(x,y) x=mmin(x,y)
#define uni(x) x.erase(unique(all(x)),x.end())
#define exist(x,y) (find(all(x),y)!=x.end())
#define bcnt __builtin_popcountll

#define INF INT_MAX/3
#define mod 1000000007

#define MAX_V 100010

struct edge{ int to,cap,rev; };
vector<edge> g[MAX_V];
int level[MAX_V];
int iter[MAX_V];

void add_edge_f(int from,int to,int cap){
  g[from].push_back((edge){to,cap,(int)g[to].size()});
  g[to].push_back((edge){from,0,(int)g[from].size()-1});
}

void bfs_f(int s){
  memset(level,-1,sizeof(level));
  queue<int> que;
  level[s]=0;
  que.push(s);
  while(!que.empty()){
    int v=que.front(); que.pop();
    for(int i=0;i<(int)g[v].size();i++){
      edge &e=g[v][i];
      if(e.cap>0&&level[e.to]<0){
        level[e.to]=level[v]+1;
        que.push(e.to);
      }
    }
  }
}

int min_dist_f(int s, int t){
  memset(level,-1,sizeof(level));
  queue<int> que;
  level[s]=0;
  que.push(s);
  while(!que.empty()){
    int v=que.front(); que.pop();
    for(int i=0;i<(int)g[v].size();i++){
      edge &e=g[v][i];
      if(e.cap>0&&level[e.to]<0){
        level[e.to]=level[v]+1;
        que.push(e.to);
      }
    }
  }
  return level[t];
}

int dfs_f(int v,int t,int f){
  if(v==t)return f;
  for(int &i=iter[v];i<(int)g[v].size();i++){
    edge &e=g[v][i];
    if(e.cap>0&&level[v]<level[e.to]){
      int d=dfs_f(e.to,t,min(f,e.cap));
      if(d>0){
        e.cap-=d;
        g[e.to][e.rev].cap+=d;
        return d;
      }
    }
  }
  return 0;
}

int max_flow(int s,int t){
  int flow=0;
  while(1){
    bfs_f(s);
    if(level[t]<0)return flow;
    memset(iter,0,sizeof(iter));
    int f;
    while((f=dfs_f(s,t,INF))>0){
      flow+=f;
    }
  }
}

int V;
vector<int> G[MAX_V];
vector<int> rG[MAX_V];
vector<int> vs;
bool used[MAX_V];
int cmp[MAX_V];

void add_edge(int from,int to){
  G[from].push_back(to);
  rG[to].push_back(from);
}

void dfs(int v){
  used[v]=true;
  for(int i=0;i<(int)G[v].size();i++){
    if(!used[G[v][i]])dfs(G[v][i]);
  }
  vs.push_back(v);
}

void rdfs(int v,int k){
  used[v]=true;
  cmp[v]=k;
  for(int i=0;i<(int)rG[v].size();i++){
    if(!used[rG[v][i]])rdfs(rG[v][i],k);
  }
}

int scc(){
  memset(used,0,sizeof(used));
  vs.clear();
  for(int v=0;v<V;v++){
    if(!used[v])dfs(v);
  }
  memset(used,0,sizeof(used));
  int k=0;
  for(int i=(int)vs.size()-1;i>=0;i--){
    if(!used[vs[i]])rdfs(vs[i],k++);
  }
  return k;
}

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N,M;
  cin>>N>>M;
  rep(i,M){
    int a,b;
    cin>>a>>b;
    a--;b--;
    add_edge(a,b);
  }
  V=N;
  int K=scc();
  if(K==1){
    cout<<0<<endl;
    return 0;
  }

  vector<int> ideg(K,0),odeg(K,0);
  rep(i,N){
    for(int v : G[i]){
      if(cmp[i]==cmp[v])continue;
      odeg[cmp[i]]++;
      ideg[cmp[v]]++;
    }
  }

  int izcnt=0,ozcnt=0;
  int icmp=-1,ocmp=-1;
  rep(i,K){
    if(ideg[i]==0){
      izcnt++;
      icmp=i;
    }
    if(odeg[i]==0){
      ozcnt++;
      ocmp=i;
    }
  }
  if(izcnt>1||ozcnt>1){
    cout<<-1<<endl;
    return 0;
  }

  int source=N,sink=N+1;
  rep(i,N){
    if(cmp[i]==icmp){
      for(int v : G[i]){
        if(cmp[v]==icmp)continue;
        if(cmp[v]==ocmp){
          add_edge_f(source,sink,1);
        }else{
          add_edge_f(source,v,1);
        }
      }
    }else if(cmp[i]==ocmp){

    }else{
      for(int v : G[i]){
        if(cmp[v]==ocmp){
          add_edge_f(i,sink,1);
        }else{
          add_edge_f(i,v,1);
        }
      }
    }
  }

  int min_d = min_dist_f(source,sink);
  int max_f = max_flow(source,sink);
  if(max_f>1) cout<<min_d<<endl;
  else cout<<-1<<endl;

  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 25028
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;

#define fi first
#define se second
#define repl(i,a,b) for(ll i=(ll)(a);i<(ll)(b);i++)
#define rep(i,n) repl(i,0,n)
#define all(x) (x).begin(),(x).end()
#define dbg(x) cout<<#x"="<<x<<endl
#define mmax(x,y) (x>y?x:y)
#define mmin(x,y) (x<y?x:y)
#define maxch(x,y) x=mmax(x,y)
#define minch(x,y) x=mmin(x,y)
#define uni(x) x.erase(unique(all(x)),x.end())
#define exist(x,y) (find(all(x),y)!=x.end())
#define bcnt __builtin_popcountll

#define INF INT_MAX/3
#define mod 1000000007

#define MAX_V 100010

struct edge{ int to,cap,rev; };
vector<edge> g[MAX_V];
int level[MAX_V];
int iter[MAX_V];

void add_edge_f(int from,int to,int cap){
  g[from].push_back((edge){to,cap,(int)g[to].size()});
  g[to].push_back((edge){from,0,(int)g[from].size()-1});
}

void bfs_f(int s){
  memset(level,-1,sizeof(level));
  queue<int> que;
  level[s]=0;
  que.push(s);
  while(!que.empty()){
    int v=que.front(); que.pop();
    for(int i=0;i<(int)g[v].size();i++){
      edge &e=g[v][i];
      if(e.cap>0&&level[e.to]<0){
        level[e.to]=level[v]+1;
        que.push(e.to);
      }
    }
  }
}

int min_dist_f(int s, int t){
  memset(level,-1,sizeof(level));
  queue<int> que;
  level[s]=0;
  que.push(s);
  while(!que.empty()){
    int v=que.front(); que.pop();
    for(int i=0;i<(int)g[v].size();i++){
      edge &e=g[v][i];
      if(e.cap>0&&level[e.to]<0){
        level[e.to]=level[v]+1;
        que.push(e.to);
      }
    }
  }
  return level[t];
}

int dfs_f(int v,int t,int f){
  if(v==t)return f;
  for(int &i=iter[v];i<(int)g[v].size();i++){
    edge &e=g[v][i];
    if(e.cap>0&&level[v]<level[e.to]){
      int d=dfs_f(e.to,t,min(f,e.cap));
      if(d>0){
        e.cap-=d;
        g[e.to][e.rev].cap+=d;
        return d;
      }
    }
  }
  return 0;
}

int max_flow(int s,int t){
  int flow=0;
  while(1){
    bfs_f(s);
    if(level[t]<0)return flow;
    memset(iter,0,sizeof(iter));
    int f;
    while((f=dfs_f(s,t,INF))>0){
      flow+=f;
    }
  }
}

int V;
vector<int> G[MAX_V];
vector<int> rG[MAX_V];
vector<int> vs;
bool used[MAX_V];
int cmp[MAX_V];

void add_edge(int from,int to){
  G[from].push_back(to);
  rG[to].push_back(from);
}

void dfs(int v){
  used[v]=true;
  for(int i=0;i<(int)G[v].size();i++){
    if(!used[G[v][i]])dfs(G[v][i]);
  }
  vs.push_back(v);
}

void rdfs(int v,int k){
  used[v]=true;
  cmp[v]=k;
  for(int i=0;i<(int)rG[v].size();i++){
    if(!used[rG[v][i]])rdfs(rG[v][i],k);
  }
}

int scc(){
  memset(used,0,sizeof(used));
  vs.clear();
  for(int v=0;v<V;v++){
    if(!used[v])dfs(v);
  }
  memset(used,0,sizeof(used));
  int k=0;
  for(int i=(int)vs.size()-1;i>=0;i--){
    if(!used[vs[i]])rdfs(vs[i],k++);
  }
  return k;
}

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N,M;
  cin>>N>>M;
  rep(i,M){
    int a,b;
    cin>>a>>b;
    a--;b--;
    add_edge(a,b);
  }
  V=N;
  int K=scc();
  if(K==1){
    cout<<0<<endl;
    return 0;
  }

  vector<int> ideg(K,0),odeg(K,0);
  rep(i,N){
    for(int v : G[i]){
      odeg[cmp[i]]++;
      ideg[cmp[v]]++;
    }
  }

  int izcnt=0,ozcnt=0;
  int icmp=-1,ocmp=-1;
  rep(i,K){
    if(ideg[i]==0){
      izcnt++;
      icmp=i;
    }
    if(odeg[i]==0){
      ozcnt++;
      ocmp=i;
    }
  }
  if(izcnt>1||ozcnt>1){
    cout<<-1<<endl;
    return 0;
  }

  int source=N,sink=N+1;
  rep(i,N){
    if(cmp[i]==icmp){
      for(int v : G[i]){
        if(cmp[v]==icmp)continue;
        if(cmp[v]==ocmp){
          add_edge_f(source,sink,1);
        }else{
          add_edge_f(source,v,1);
        }
      }
    }else if(cmp[i]==ocmp){

    }else{
      for(int v : G[i]){
        if(cmp[v]==ocmp){
          add_edge_f(i,sink,1);
        }else{
          add_edge_f(i,v,1);
        }
      }
    }
  }

  int min_d = min_dist_f(source,sink);
  int max_f = max_flow(source,sink);
  if(max_f>1)cout<<min_d<<endl;
  else cout<<-1<<endl;

  return 0;
}
accuracy: 0.5
time_ms: 40
memory_kb: 22612
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> P;

#define fi first
#define se second
#define repl(i,a,b) for(ll i=(ll)(a);i<(ll)(b);i++)
#define rep(i,n) repl(i,0,n)
#define all(x) (x).begin(),(x).end()
#define dbg(x) cout<<#x"="<<x<<endl
#define mmax(x,y) (x>y?x:y)
#define mmin(x,y) (x<y?x:y)
#define maxch(x,y) x=mmax(x,y)
#define minch(x,y) x=mmin(x,y)
#define uni(x) x.erase(unique(all(x)),x.end())
#define exist(x,y) (find(all(x),y)!=x.end())
#define bcnt __builtin_popcountll

#define INF INT_MAX/3
#define mod 1000000007

#define MAX_V 100010

struct edge{ int to,cap,rev; };
vector<edge> g[MAX_V];
int level[MAX_V];
int iter[MAX_V];

void add_edge_f(int from,int to,int cap){
  g[from].push_back((edge){to,cap,(int)g[to].size()});
  g[to].push_back((edge){from,0,(int)g[from].size()-1});
}

void bfs_f(int s){
  memset(level,-1,sizeof(level));
  queue<int> que;
  level[s]=0;
  que.push(s);
  while(!que.empty()){
    int v=que.front(); que.pop();
    for(int i=0;i<(int)g[v].size();i++){
      edge &e=g[v][i];
      if(e.cap>0&&level[e.to]<0){
        level[e.to]=level[v]+1;
        que.push(e.to);
      }
    }
  }
}

int min_dist_f(int s, int t){
  memset(level,-1,sizeof(level));
  queue<int> que;
  level[s]=0;
  que.push(s);
  while(!que.empty()){
    int v=que.front(); que.pop();
    for(int i=0;i<(int)g[v].size();i++){
      edge &e=g[v][i];
      if(e.cap>0&&level[e.to]<0){
        level[e.to]=level[v]+1;
        que.push(e.to);
      }
    }
  }
  return level[t];
}

int dfs_f(int v,int t,int f){
  if(v==t)return f;
  for(int &i=iter[v];i<(int)g[v].size();i++){
    edge &e=g[v][i];
    if(e.cap>0&&level[v]<level[e.to]){
      int d=dfs_f(e.to,t,min(f,e.cap));
      if(d>0){
        e.cap-=d;
        g[e.to][e.rev].cap+=d;
        return d;
      }
    }
  }
  return 0;
}

int max_flow(int s,int t){
  int flow=0;
  while(1){
    bfs_f(s);
    if(level[t]<0)return flow;
    memset(iter,0,sizeof(iter));
    int f;
    while((f=dfs_f(s,t,INF))>0){
      flow+=f;
    }
  }
}

int V;
vector<int> G[MAX_V];
vector<int> rG[MAX_V];
vector<int> vs;
bool used[MAX_V];
int cmp[MAX_V];

void add_edge(int from,int to){
  G[from].push_back(to);
  rG[to].push_back(from);
}

void dfs(int v){
  used[v]=true;
  for(int i=0;i<(int)G[v].size();i++){
    if(!used[G[v][i]])dfs(G[v][i]);
  }
  vs.push_back(v);
}

void rdfs(int v,int k){
  used[v]=true;
  cmp[v]=k;
  for(int i=0;i<(int)rG[v].size();i++){
    if(!used[rG[v][i]])rdfs(rG[v][i],k);
  }
}

int scc(){
  memset(used,0,sizeof(used));
  vs.clear();
  for(int v=0;v<V;v++){
    if(!used[v])dfs(v);
  }
  memset(used,0,sizeof(used));
  int k=0;
  for(int i=(int)vs.size()-1;i>=0;i--){
    if(!used[vs[i]])rdfs(vs[i],k++);
  }
  return k;
}

int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);

  int N,M;
  cin>>N>>M;
  rep(i,M){
    int a,b;
    cin>>a>>b;
    a--;b--;
    add_edge(a,b);
  }
  V=N;
  int K=scc();
  if(K==1){
    cout<<0<<endl;
    return 0;
  }

  vector<int> ideg(K,0),odeg(K,0);
  rep(i,N){
    for(int v : G[i]){
      odeg[cmp[i]]++;
      ideg[cmp[v]]++;
    }
  }

  int izcnt=0,ozcnt=0;
  int icmp=-1,ocmp=-1;
  rep(i,K){
    if(ideg[i]==0){
      izcnt++;
      icmp=i;
    }
    if(odeg[i]==0){
      ozcnt++;
      ocmp=i;
    }
  }
  if(izcnt>1||ozcnt>1){
    cout<<-1<<endl;
  }

  int source=N,sink=N+1;
  rep(i,N){
    if(cmp[i]==icmp){
      for(int v : G[i]){
        if(cmp[v]==icmp)continue;
        if(cmp[v]==ocmp){
          add_edge_f(source,sink,1);
        }else{
          add_edge_f(source,v,1);
        }
      }
    }else if(cmp[i]==ocmp){

    }else{
      for(int v : G[i]){
        if(cmp[v]==ocmp){
          add_edge_f(i,sink,1);
        }else{
          add_edge_f(i,v,1);
        }
      }
    }
  }

  int min_d = min_dist_f(source,sink);
  int max_f = max_flow(source,sink);
  if(max_f>1)cout<<min_d<<endl;
  else cout<<-1<<endl;

  return 0;
}
accuracy: 0.28378378378378377
time_ms: 30
memory_kb: 22692
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T,class U> using P = pair<T,U>;
template<class T> using vec = vector<T>;
template<class T> using vvec = vector<vec<T>>;

class strong_components{
public:
	vector<vector<int>> v,rv,nv;
	vector<int> rs,visited,cmp,cmp_size;
	void dfs(int n){
		visited[n] = 1;
		for(auto x:v[n]) if(!visited[x]) dfs(x);
		rs.push_back(n);
	}
	void rdfs(int n,int cnt){
		visited[n] = 1;
		cmp[n] = cnt;
		for(auto x:rv[n]) if(!visited[x]) rdfs(x,cnt);
	}
	strong_components(int N,vector<vector<int>>& graph){
		v = graph;
		rv = vector<vector<int>>(N);
		visited = cmp = cmp_size = vector<int>(N,0);
		for(int i=0;i<N;i++) for(auto x:v[i]) rv[x].push_back(i);
		for(int i=0;i<N;i++) if(!visited[i]) dfs(i);
		for(int i=0;i<N;i++) visited[i] = 0;
		int now = 0;
		for(int i=rs.size()-1;i>=0;i--) if(!visited[rs[i]]) rdfs(rs[i],now++);
		nv = vector<vector<int>>(now);
		for(int i=0;i<N;i++){
			for(auto x:v[i]){
				if(cmp[i]!=cmp[x]){
					nv[cmp[i]].push_back(cmp[x]);
				}
			}
		}
		for(int i=0;i<N;i++) cmp_size[cmp[i]]++;
	}
	int find(int n){return cmp[n];}
	int size(int n){return cmp_size[cmp[n]];}
	bool is_same_group(int a,int b){return cmp[a]==cmp[b];}
};

constexpr int inf = 1e9;
class network_flow{
private:
	struct edge{int to, cap, rev;};
	vector<vector<edge>> G;
	vector<bool> used;
public:
	network_flow(int N){
		G = vector<vector<edge>>(N+1);
		used = vector<bool>(N+1,0); 
	}
	void add_edge(int from, int to, int cap){
		G[from].push_back((edge){to,cap,(int) G[to].size()});
		G[to].push_back((edge){from,0,(int) G[from].size()-1});
	}
	int dfs(int v,int t,int f){
		if(v==t) return f;
		used[v] = true;
		for(int i=0;i<G[v].size();i++){
			edge &e = G[v][i];
			if(!used[e.to] && e.cap>0){
				int d = dfs(e.to,t,min(f,e.cap));
				if(d>0){
					e.cap -= d;
					G[e.to][e.rev].cap += d;
					return d;
				}
			}
		}
		return 0;
	}
	int max_flow(int s,int t){
		int flow = 0;
		for(;;){
			if(flow>1) return flow;
			for(int i=0;i<(int)used.size();i++) used[i] = 0;
			int f = dfs(s,t,inf);
			if(f==0) return flow;
			flow += f;
		}
	}
};

int main(){
	int N,M;
	cin >> N >> M;
	vvec<int> g(N);
	for(int i=0;i<M;i++){
		int a,b;
		cin >> a >> b;
		a--; b--;
		g[a].push_back(b);
	}
	strong_components SCC(N,g);
	vvec<int> cmp_g = SCC.nv;
	int n = cmp_g.size();
	if(n==1){
		cout << 0 << "\n";
		return 0;
	}
	vec<int> indeg(n);
	int c = 0,t = 0;
	for(int i=0;i<n;i++){
		if(cmp_g[i].size()==0){
			t = i;
			c++;
		}
		for(auto& x:cmp_g[i]) indeg[x]++;
	}
	if(c>1 || count(indeg.begin(),indeg.end(),0)>1){
		cout << -1 << "\n";
		return 0;
	}
	int s = find(indeg.begin(),indeg.end(),0)-indeg.begin();
	vec<int> dist(N,inf);
	queue<int> Q;
	for(int i=0;i<N;i++){
		if(SCC.find(i)==s){
			dist[i] = 0;
			Q.push(i);
		}
	}
	while(!Q.empty()){
		int cur = Q.front(); Q.pop();
		for(auto& to:g[cur]){
			if(dist[to]>dist[cur]+1){
				dist[to] = dist[cur]+1;
				Q.push(to);
			}
		}
	}
	int ans = inf;
	for(int i=0;i<N;i++) if(SCC.find(i)==t) ans = min(ans,dist[i]);
	network_flow flow(N+2);
	int S = N,T = N+1;
	for(int i=0;i<N;i++){
		for(auto& x:g[i]) flow.add_edge(i,x,1);
		if(SCC.find(i)==s) flow.add_edge(S,i,2);
		if(SCC.find(i)==t) flow.add_edge(i,T,2);
	}
	if(flow.max_flow(S,T)<2){
		cout << -1 << "\n";
	}else{
		cout << ans << "\n";
	}
}
accuracy: 1
time_ms: 70
memory_kb: 42040
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
template<class T,class U> using P = pair<T,U>;
template<class T> using vec = vector<T>;
template<class T> using vvec = vector<vec<T>>;

class strong_components{
public:
	vector<vector<int>> v,rv,nv;
	vector<int> rs,visited,cmp,cmp_size;
	void dfs(int n){
		visited[n] = 1;
		for(auto x:v[n]) if(!visited[x]) dfs(x);
		rs.push_back(n);
	}
	void rdfs(int n,int cnt){
		visited[n] = 1;
		cmp[n] = cnt;
		for(auto x:rv[n]) if(!visited[x]) rdfs(x,cnt);
	}
	strong_components(int N,vector<vector<int>>& graph){
		v = graph;
		rv = vector<vector<int>>(N);
		visited = cmp = cmp_size = vector<int>(N,0);
		for(int i=0;i<N;i++) for(auto x:v[i]) rv[x].push_back(i);
		for(int i=0;i<N;i++) if(!visited[i]) dfs(i);
		for(int i=0;i<N;i++) visited[i] = 0;
		int now = 0;
		for(int i=rs.size()-1;i>=0;i--) if(!visited[rs[i]]) rdfs(rs[i],now++);
		nv = vector<vector<int>>(now);
		for(int i=0;i<N;i++){
			for(auto x:v[i]){
				if(cmp[i]!=cmp[x]){
					nv[cmp[i]].push_back(cmp[x]);
				}
			}
		}
		for(int i=0;i<N;i++) cmp_size[cmp[i]]++;
	}
	int find(int n){return cmp[n];}
	int size(int n){return cmp_size[cmp[n]];}
	bool is_same_group(int a,int b){return cmp[a]==cmp[b];}
};

constexpr int inf = 1e9;
class network_flow{
private:
	struct edge{int to, cap, rev;};
	vector<vector<edge>> G;
	vector<bool> used;
public:
	network_flow(int N){
		G = vector<vector<edge>>(N+1);
		used = vector<bool>(N+1,0); 
	}
	void add_edge(int from, int to, int cap){
		G[from].push_back((edge){to,cap,(int) G[to].size()});
		G[to].push_back((edge){from,0,(int) G[from].size()-1});
	}
	int dfs(int v,int t,int f){
		if(v==t) return f;
		used[v] = true;
		for(int i=0;i<G[v].size();i++){
			edge &e = G[v][i];
			if(!used[e.to] && e.cap>0){
				int d = dfs(e.to,t,min(f,e.cap));
				if(d>0){
					e.cap -= d;
					G[e.to][e.rev].cap += d;
					return d;
				}
			}
		}
		return 0;
	}
	int max_flow(int s,int t){
		int flow = 0;
		for(;;){
			if(flow>1) return flow;
			for(int i=0;i<(int)used.size();i++) used[i] = 0;
			int f = dfs(s,t,inf);
			if(f==0) return flow;
			flow += f;
		}
	}
};

int main(){
	int N,M;
	cin >> N >> M;
	vvec<int> g(N);
	for(int i=0;i<M;i++){
		int a,b;
		cin >> a >> b;
		a--; b--;
		g[a].push_back(b);
	}
	strong_components SCC(N,g);
	vvec<int> cmp_g = SCC.nv;
	int n = cmp_g.size();
	if(n==1){
		cout << 0 << "\n";
		return 0;
	}
	vec<int> indeg(n);
	int c = 0,t = 0;
	for(int i=0;i<n;i++){
		if(cmp_g[i].size()==0){
			t = i;
			c++;
		}
		for(auto& x:cmp_g[i]) indeg[x]++;
	}
	if(c>1 || count(indeg.begin(),indeg.end(),0)>1){
		cout << -1 << "\n";
		return 0;
	}
	int s = find(indeg.begin(),indeg.end(),0)-indeg.begin();
	vec<int> dist(N,inf);
	queue<int> Q;
	for(int i=0;i<N;i++){
		if(SCC.find(i)==s){
			dist[i] = 0;
			Q.push(i);
		}
	}
	while(!Q.empty()){
		int cur = Q.front(); Q.pop();
		for(auto& to:g[cur]){
			if(dist[to]>dist[cur]+1){
				dist[to] = dist[cur]+1;
				Q.push(to);
			}
		}
	}
	int ans = inf;
	for(int i=0;i<N;i++) if(SCC.find(i)==t) ans = min(ans,dist[i]);
	network_flow flow(n);
	for(int i=0;i<n;i++){
		for(auto& x:cmp_g[i]) flow.add_edge(i,x,1);
	}
	if(flow.max_flow(s,t)<2){
		cout << -1 << "\n";
	}else{
		cout << ans << "\n";
	}
}
accuracy: 0.35135135135135137
time_ms: 50
memory_kb: 25896
final_rank: 19

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-12;
const ld pi = acos(-1.0);


struct graph {
private:
	int n;
	vector<vector<int>> G, rG;
	vector<bool> used;
	vector<int> vs;

	int mk;
	vector<vector<int>> fG;
	vector<vector<int>> ori;
	vector<int> trans;
public:
	graph(int sz) {
		n = sz;
		G.resize(n);
		rG.resize(n);
		used.resize(n);

		fG.resize(n);
		trans.resize(n, -1);
		ori.resize(n);
	}
	void add_edge(int a, int b) {
		G[a].push_back(b);
		rG[b].push_back(a);
	}
	void dfs(int v) {
		used[v] = true;
		rep(i, G[v].size()) {
			if (!used[G[v][i]])dfs(G[v][i]);
		}
		vs.push_back(v);
	}
	void rdfs(int v, int k) {
		used[v] = true;
		queue<int> q; q.push(v);
		vector<int> c;
		while (!q.empty()) {
			int id = q.front(); q.pop();
			ori[k].push_back(id);
			rep(j, rG[id].size()) {
				int to = rG[id][j];
				if (used[to]) {
					if (trans[to] >= 0)c.push_back(trans[to]);
					continue;
				}
				used[to] = true; q.push(to);
			}
		}
		sort(c.begin(), c.end());
		int len = unique(c.begin(), c.end()) - c.begin();
		rep(i, len) {
			fG[c[i]].push_back(k);
		}
		rep(i, ori[k].size()) {
			trans[ori[k][i]] = k;
		}
	}
	void scc() {
		fill(used.begin(), used.end(), false);
		rep(i, n) {
			if (!used[i])dfs(i);
		}
		fill(used.begin(), used.end(), false);
		int k = 0;
		per(i, (int)vs.size()) {
			if (!used[vs[i]]) {
				rdfs(vs[i], k); k++;
			}
		}
		mk = k;
	}
	void query() {
		if (mk == 1) {
			cout << 0 << "\n"; return;
		}
		vector<int> cnt(mk);
		rep(i, mk)for (int to : fG[i])cnt[to]++;
		vector<int> sta, goa;
		rep(i, mk) {
			if (fG[i].empty())goa.push_back(i);
			if (cnt[i] == 0)sta.push_back(i);
		}
		if (sta.size() > 1 || goa.size() > 1) {
			cout << -1 << "\n"; return;
		}
		vector<int> pre(n);
		vector<int> dist(n, mod);
		queue<int> q;
		for (int id : ori[sta[0]]) {
			dist[id] = 0; pre[id] = -1;
			q.push(id);
		}
		while (!q.empty()) {
			int v = q.front(); q.pop();
			for (int to : G[v]) {
				if (dist[v] + 1 < dist[to]) {
					dist[to] = dist[v] + 1;
					pre[to] = v;
					q.push(to);
				}
			}
		}
		vector<vector<int>> g(n);
		vector<int> ban(n,-1);
		int ans = mod;
		int las = 0;
		for (int id : ori[goa[0]]) {
			if (ans > dist[id]) {
				ans = dist[id]; las = id;
			}
		}
		while (pre[las]>= 0) {
			int p = pre[las];
			g[las].push_back(p);
			ban[p] = las;
			las = p;
		}
		rep(i, n)for (int to : G[i])if (ban[i] != to) {
			g[i].push_back(to);
		}
		vector<bool> exi(n, false);
		q.push(las);
		while (!q.empty()) {
			int v = q.front(); q.pop();
			for (int to : g[v])if (!exi[to]) {
				exi[to] = true;
				q.push(to);
			}
		}
		rep(i, n)if (!exi[i]) {
			cout << -1 << "\n"; return;
		}
		cout << ans << "\n";
	}
};


void solve() {
	int n, m; cin >> n >> m;
	graph g(n);
	rep(i, m) {
		int a, b; cin >> a >> b; a--; b--;
		g.add_edge(a, b);
	}

	g.scc();
	g.query();
}





signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	solve();
	return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 33484
final_rank: 3

code_snippet: #line 1 "other/l2.cpp"
#include <bits/extc++.h>

#line 5 "Library/config.hpp"
namespace config {
const auto start_time{std::chrono::system_clock::now()};
int64_t elapsed() {
  using namespace std::chrono;
  const auto end_time{system_clock::now()};
  return duration_cast<milliseconds>(end_time - start_time).count();
}
__attribute__((constructor)) void setup() {
  using namespace std;
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout << fixed << setprecision(15);
#ifdef _buffer_check
  atexit([] {
    char bufc;
    if (cin >> bufc)
      cerr << "\n\033[43m\033[30mwarning: buffer not empty.\033[0m\n\n";
  });
#endif
}
unsigned cases(void), caseid = 1;
template <class C> void main() {
  for (const unsigned total = cases(); caseid <= total; ++caseid) C();
}
}  // namespace config
#line 3 "Library/gcc_builtin.hpp"
namespace workspace {
constexpr int clz32(const uint32_t &n) noexcept { return __builtin_clz(n); }
constexpr int clz64(const uint64_t &n) noexcept{ return __builtin_clzll(n); }
constexpr int ctz(const uint64_t &n) noexcept { return __builtin_ctzll(n); }
constexpr int popcnt(const uint64_t &n) noexcept { return __builtin_popcountll(n); }
} // namespace workspace
#line 2 "Library/gcc_option.hpp"
#ifdef ONLINE_JUDGE
    #pragma GCC optimize("O3")
    #pragma GCC target("avx,avx2")
    #pragma GCC optimize("unroll-loops")
#endif
#line 5 "Library/utils/binary_search.hpp"
namespace workspace {
// binary search on discrete range.
template <class iter_type, class pred_type>
std::enable_if_t<
    std::is_convertible_v<std::invoke_result_t<pred_type, iter_type>, bool>,
    iter_type>
binary_search(iter_type ok, iter_type ng, pred_type pred) {
  assert(ok != ng);
  __int128_t dist(ng - ok);
  while (dist > 1 || dist < -1) {
    iter_type mid(ok + dist / 2);
    if (pred(mid))
      ok = mid, dist -= dist / 2;
    else
      ng = mid, dist /= 2;
  }
  return ok;
}
// parallel binary search on discrete range.
template <class iter_type, class pred_type>
std::enable_if_t<std::is_convertible_v<
                     std::invoke_result_t<pred_type, std::vector<iter_type>>,
                     std::vector<bool>>,
                 std::vector<iter_type>>
binary_search(std::vector<std::pair<iter_type, iter_type>> ends,
              pred_type pred) {
  std::vector<iter_type> mids(ends.size());
  for (;;) {
    bool all_found = true;
    for (size_t i{}; i != ends.size(); ++i) {
      auto [ok, ng] = ends[i];
      iter_type mid(ok + (ng - ok) / 2);
      if (mids[i] != mid) {
        all_found = false;
        mids[i] = mid;
      }
    }
    if (all_found) break;
    auto res = pred(mids);
    for (size_t i{}; i != ends.size(); ++i) {
      (res[i] ? ends[i].first : ends[i].second) = mids[i];
    }
  }
  return mids;
}
// binary search on real numbers.
template <class real_type, class pred_type>
std::enable_if_t<
    std::is_convertible_v<std::invoke_result_t<pred_type, real_type>, bool>,
    real_type>
binary_search(real_type ok, real_type ng, const real_type eps, pred_type pred) {
  assert(ok != ng);
  while (ok + eps < ng || ng + eps < ok) {
    real_type mid{(ok + ng) / 2};
    (pred(mid) ? ok : ng) = mid;
  }
  return ok;
}
// parallel binary search on real numbers.
template <class real_type, class pred_type>
std::enable_if_t<std::is_convertible_v<
                     std::invoke_result_t<pred_type, std::vector<real_type>>,
                     std::vector<bool>>,
                 std::vector<real_type>>
binary_search(std::vector<std::pair<real_type, real_type>> ends,
              const real_type eps, pred_type pred) {
  std::vector<real_type> mids(ends.size());
  for (;;) {
    bool all_found = true;
    for (size_t i{}; i != ends.size(); ++i) {
      auto [ok, ng] = ends[i];
      if (ok + eps < ng || ng + eps < ok) {
        all_found = false;
        mids[i] = (ok + ng) / 2;
      }
    }
    if (all_found) break;
    auto res = pred(mids);
    for (size_t i{}; i != ends.size(); ++i) {
      (res[i] ? ends[i].first : ends[i].second) = mids[i];
    }
  }
  return mids;
}
}  // namespace workspace
#line 3 "Library/utils/casefmt.hpp"
namespace workspace {
std::ostream &casefmt(std::ostream& os) { return os << "Case #" << config::caseid << ": "; }
} // namespace workspace
#line 3 "Library/utils/chval.hpp"
namespace workspace {
template <class T, class Comp = std::less<T>> bool chle(T &x, const T &y, Comp comp = Comp()) { return comp(y, x) ? x = y, true : false; }
template <class T, class Comp = std::less<T>> bool chge(T &x, const T &y, Comp comp = Comp()) { return comp(x, y) ? x = y, true : false; }
} // namespace workspace
#line 3 "Library/utils/fixed_point.hpp"
namespace workspace {
// specify the return type of lambda.
template <class lambda_type>
class fixed_point
{
    lambda_type func;
public:
    fixed_point(lambda_type &&f) : func(std::move(f)) {}
    template <class... Args> auto operator()(Args &&... args) const { return func(*this, std::forward<Args>(args)...); }
};
} // namespace workspace
#line 3 "Library/utils/sfinae.hpp"
#include <type_traits>

template <class type, template <class> class trait>
using enable_if_trait_type = typename std::enable_if<trait<type>::value>::type;

template <class Container>
using element_type = typename std::decay<decltype(
    *std::begin(std::declval<Container&>()))>::type;

template <class T, class = void> struct is_integral_ext : std::false_type {};
template <class T>
struct is_integral_ext<
    T, typename std::enable_if<std::is_integral<T>::value>::type>
    : std::true_type {};
template <> struct is_integral_ext<__int128_t> : std::true_type {};
template <> struct is_integral_ext<__uint128_t> : std::true_type {};
#if __cplusplus >= 201402
template <class T>
constexpr static bool is_integral_ext_v = is_integral_ext<T>::value;
#endif

template <typename T, typename = void> struct multiplicable_uint {
  using type = uint_least32_t;
};
template <typename T>
struct multiplicable_uint<T, typename std::enable_if<(2 < sizeof(T))>::type> {
  using type = uint_least64_t;
};
template <typename T>
struct multiplicable_uint<T, typename std::enable_if<(4 < sizeof(T))>::type> {
  using type = __uint128_t;
};
#line 7 "Library/utils/hash.hpp"
namespace workspace {
template <class T, class = void>
struct hash : std::hash<T> {};
template <class Unique_bits_type>
struct hash<Unique_bits_type, enable_if_trait_type<Unique_bits_type, std::has_unique_object_representations>>
{
    size_t operator()(uint64_t x) const
    {
        static const uint64_t m = std::random_device{}();
        x ^= x >> 23;
        // x *= 0x2127599bf4325c37ULL;
        x ^= m;
        x ^= x >> 47;
        return x - (x >> 32);
    }
};
template <class Key>
size_t hash_combine(const size_t &seed, const Key &key)
{
    return seed ^ (hash<Key>()(key) + 0x9e3779b9 /* + (seed << 6) + (seed >> 2) */ );
}
template <class T1, class T2>
struct hash<std::pair<T1, T2>>
{
    size_t operator()(const std::pair<T1, T2> &pair) const
    {
        return hash_combine(hash<T1>()(pair.first), pair.second);
    }
};
template <class... T>
class hash<std::tuple<T...>>
{
    template <class Tuple, size_t index = std::tuple_size<Tuple>::value - 1> struct tuple_hash { static uint64_t apply(const Tuple &t) { return hash_combine(tuple_hash<Tuple, index - 1>::apply(t), std::get<index>(t)); } };
    template <class Tuple> struct tuple_hash<Tuple, size_t(-1)> { static uint64_t apply(const Tuple &t) { return 0; } };
public:
    uint64_t operator()(const std::tuple<T...> &t) const { return tuple_hash<std::tuple<T...>>::apply(t); }
};
template <class hash_table>
struct hash_table_wrapper : hash_table
{
    using key_type = typename hash_table::key_type;
    size_t count(const key_type &key) const { return hash_table::find(key) != hash_table::end(); }
    template <class... Args> auto emplace(Args&&... args) { return hash_table::insert(typename hash_table::value_type(args...)); }
};
template <class Key, class Mapped = __gnu_pbds::null_type>
using cc_hash_table = hash_table_wrapper<__gnu_pbds::cc_hash_table<Key, Mapped, hash<Key>>>;
template <class Key, class Mapped = __gnu_pbds::null_type>
using gp_hash_table = hash_table_wrapper<__gnu_pbds::gp_hash_table<Key, Mapped, hash<Key>>>;
template <class Key, class Mapped>
using unordered_map = std::unordered_map<Key, Mapped, hash<Key>>;
template <class Key>
using unordered_set = std::unordered_set<Key, hash<Key>>;
} // namespace workspace
#line 3 "Library/utils/make_vector.hpp"
namespace workspace {
template <typename T, size_t N>
constexpr auto make_vector(size_t* sizes, T const& init = T()) {
  if constexpr (N)
    return std::vector(*sizes, make_vector<T, N - 1>(std::next(sizes), init));
  else
    return init;
}
template <typename T, size_t N>
constexpr auto make_vector(const size_t (&sizes)[N], T const& init = T()) {
  return make_vector<T, N>((size_t*)sizes, init);
}
}  // namespace workspace
#line 3 "Library/utils/read.hpp"
namespace workspace {
// read with std::cin.
template <class T = void>
struct read
{
    typename std::remove_const<T>::type value;
    template <class... types>
    read(types... args) : value(args...) { std::cin >> value; }
    operator T() const { return value; }
};
template <>
struct read<void>
{
    template <class T>
    operator T() const { T value; std::cin >> value; return value; }
};
} // namespace workspace
#line 4 "Library/utils/stream.hpp"

#line 6 "Library/utils/stream.hpp"
namespace std {
template <class T, class U> istream &operator>>(istream &is, pair<T, U> &p) {
  return is >> p.first >> p.second;
}
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
  return os << p.first << ' ' << p.second;
}
template <class tuple_t, size_t index> struct tuple_is {
  static istream &apply(istream &is, tuple_t &t) {
    tuple_is<tuple_t, index - 1>::apply(is, t);
    return is >> get<index>(t);
  }
};
template <class tuple_t> struct tuple_is<tuple_t, SIZE_MAX> {
  static istream &apply(istream &is, tuple_t &t) { return is; }
};
template <class... T> istream &operator>>(istream &is, tuple<T...> &t) {
  return tuple_is<tuple<T...>, tuple_size<tuple<T...>>::value - 1>::apply(is,
                                                                          t);
}
template <class tuple_t, size_t index> struct tuple_os {
  static ostream &apply(ostream &os, const tuple_t &t) {
    tuple_os<tuple_t, index - 1>::apply(os, t);
    return os << ' ' << get<index>(t);
  }
};
template <class tuple_t> struct tuple_os<tuple_t, 0> {
  static ostream &apply(ostream &os, const tuple_t &t) {
    return os << get<0>(t);
  }
};
template <class tuple_t> struct tuple_os<tuple_t, SIZE_MAX> {
  static ostream &apply(ostream &os, const tuple_t &t) { return os; }
};
template <class... T> ostream &operator<<(ostream &os, const tuple<T...> &t) {
  return tuple_os<tuple<T...>, tuple_size<tuple<T...>>::value - 1>::apply(os,
                                                                          t);
}
template <class Container, typename Value = element_type<Container>>
typename enable_if<!is_same<typename decay<Container>::type, string>::value &&
                       !is_same<typename decay<Container>::type, char *>::value,
                   istream &>::type
operator>>(istream &is, Container &cont) {
  for (auto &&e : cont) is >> e;
  return is;
}
template <class Container, typename Value = element_type<Container>>
typename enable_if<!is_same<typename decay<Container>::type, string>::value &&
                       !is_same<typename decay<Container>::type, char *>::value,
                   ostream &>::type
operator<<(ostream &os, const Container &cont) {
  bool head = true;
  for (auto &&e : cont) head ? head = 0 : (os << ' ', 0), os << e;
  return os;
}
}  // namespace std
#line 14 "other/l2.cpp"
namespace workspace {
constexpr char eol = '\n';
using namespace std;
using i32 = int_least32_t;
using i64 = int_least64_t;
using i128 = __int128_t;
using u32 = uint_least32_t;
using u64 = uint_least64_t;
using u128 = __uint128_t;
template <class T, class Comp = std::less<T>>
using priority_queue = std::priority_queue<T, std::vector<T>, Comp>;
template <class T> using stack = std::stack<T, std::vector<T>>;
struct solver;
}  // namespace workspace
int main() { config::main<workspace::solver>(); }
unsigned config::cases() {
  // return -1; // not specified
  // int t; std::cin >> t; return t; // given
  return 1;
}

#line 4 "Library/graph/directed/flow/base.hpp"
// the base class of flow algorithms.
template <class cap_t, class cost_t> struct flow_base {
  struct edge_t {
    size_t src, dst;
    cap_t cap;
    cost_t cost;
    edge_t *rev;
    edge_t() = default;
    edge_t(size_t src, size_t dst, cap_t cap, edge_t *rev)
        : src(src), dst(dst), cap(cap), rev(rev) {}
    edge_t(size_t src, size_t dst, cap_t cap, cost_t cost, edge_t *rev)
        : src(src), dst(dst), cap(cap), cost(cost), rev(rev) {}
    void flow(cap_t f) { cap -= f, rev->cap += f; }
    bool avbl() const { return cap > 0; }
  };  // class edge_t

  class adj_type {
    edge_t *fst, *lst, *clst;

   public:
    template <class... Args> edge_t *emplace(Args &&... args) {
      if (lst == clst) {
        size_t len(clst - fst);
        edge_t *nfst = lst = new edge_t[len << 1];
        for (edge_t *p{fst}; p != clst; ++p, ++lst)
          p->rev->rev = lst, *lst = *p;
        delete[] fst;
        fst = nfst;
        clst = lst + len;
      }
      *lst = edge_t(args...);
      return lst++;
    }
    adj_type() : fst(new edge_t[1]), lst(fst), clst(fst + 1) {}
    ~adj_type() { delete[] fst; }
    edge_t &operator[](size_t i) {
      assert(i < size());
      return *(fst + i);
    }
    size_t size() const { return lst - fst; }
    edge_t *begin() const { return fst; }
    edge_t *end() const { return lst; }
  };  // class adj_type

  flow_base(size_t n = 0) : adjs(n) {}

  flow_base(const flow_base &other) : adjs(other.size()) {
    for (size_t node{}; node != size(); ++node)
      for (const auto &[src, dst, cap, cost, rev] : other[node])
        if (src == node) {
          edge_t *ptr = adjs[src].emplace(src, dst, cap, cost, nullptr);
          ptr->rev = adjs[dst].emplace(dst, src, rev->cap, -cost, ptr);
          rev->src = -1;
        } else {
          rev->rev->src = node;
        }
  }

  flow_base &operator=(const flow_base &rhs) {
    if (this != &rhs) adjs.swap(flow_base(rhs).adjs);
    return *this;
  }

  size_t size() const { return adjs.size(); }

  adj_type &operator[](size_t node) {
    assert(node < size());
    return adjs[node];
  }
  const adj_type &operator[](size_t node) const {
    assert(node < size());
    return adjs[node];
  }

  virtual void add_edge(size_t src, size_t dst, cap_t cap, cost_t cost) {
    assert(src < size());
    assert(dst < size());
    if (!(cap > 0) || src == dst) return;
    edge_t *ptr = adjs[src].emplace(src, dst, cap, cost, nullptr);
    ptr->rev = adjs[dst].emplace(dst, src, 0, -cost, ptr);
  }

 protected:
  std::vector<adj_type> adjs;
};  // class flow_base
#line 36 "other/l2.cpp"

template <class cap_t = int> class Dinic : public flow_base<cap_t, bool> {
  using base = flow_base<cap_t, bool>;
  using edge_t = typename base::edge_t;
  using base::adjs;

  std::vector<size_t> level;
  std::vector<edge_t *> itr;
  constexpr static size_t level_infty = -1;

  cap_t dfs(const size_t &src, const size_t &dst, cap_t bound) {
    if (src == dst || bound == 0) return bound;
    cap_t flow(0);
    for (edge_t *&e{itr[dst]}; e != adjs[dst].end(); ++e)
      if (e->rev->avbl() && level[e->dst] < level[dst])
        if (cap_t achv = dfs(src, e->dst, std::min(bound, e->rev->cap));
            achv > 0) {
          e->rev->flow(achv);
          flow += achv, bound -= achv;
          if (bound == 0) break;
        }
    return flow;
  }

 public:
  using base::size;

  Dinic(size_t n = 0) : base::flow_base(n), level(n, level_infty), itr(n) {}

  Dinic(const Dinic &other)
      : base::flow_base(other), level(other.level), itr(other.itr) {}

  Dinic &operator=(const Dinic &rhs) {
    if (this != &rhs) base::operator=(rhs), level = rhs.level, itr = rhs.itr;
    return *this;
  }

  void add_edge(size_t src, size_t dst, cap_t cap) {
    base::add_edge(src, dst, cap, false);
  }

  void add_undirected_edge(size_t src, size_t dst, cap_t cap) {
    base::add_undirected_edge(src, dst, cap, false);
  }

  int ans = -1, loop = 0;

  cap_t max_flow(size_t src, size_t dst) {
    assert(src < size());
    assert(dst < size());
    cap_t flow(0), bound(0);
    for (const edge_t &e : adjs[src]) bound += e.cap;
    for (std::vector<size_t> que(size());;
         std::fill(level.begin(), level.end(), level_infty)) {
      level[que.front() = src] = 0;
      for (auto ql{que.begin()}, qr{std::next(ql)};
           level[dst] == level_infty && ql != qr; ++ql)
        for (const edge_t &e : adjs[*ql])
          if (e.avbl() && level[e.dst] == level_infty)
            level[ *qr++ = e.dst] = level[*ql] + 1;
      if (level[dst] == level_infty) break;
      for (size_t node{}; node != size(); ++node)
        itr[node] = adjs[node].begin();
      flow += dfs(src, dst, bound);
      if (ans < 0 || (int)level[dst] < ans) ans = level[dst];
      loop++;
    }
    return flow;
  }
};  // class Dinic

#line 5 "Library/graph/directed/strongly_connected_components.hpp"
struct strongly_connected_components {
  strongly_connected_components(size_t n) : graph(n), low(n), made() {}

  // add an edge from the vertex s to the vertex t.
  void add_edge(size_t src, size_t dst) {
    assert(src < size());
    assert(dst < size());
    graph[src].emplace_back(dst);
    made = false;
  }

  // the number of the components.
  size_t count() {
    make();
    return comp_cnt;
  }

  size_t size() const { return graph.size(); }

  // the component which the vertex v belongs to.
  size_t operator[](size_t v) {
    make();
    return low[v];
  }

  // the directed acyclic graph consisting of the components.
  const std::vector<std::vector<size_t>> &shrinked_dag() {
    make();
    return dag;
  }

 protected:
  std::vector<std::vector<size_t>> graph, dag;
  std::vector<size_t> low;
  size_t comp_cnt;
  bool made;

  void make() {
    if (made) return;
    made = true, comp_cnt = 0;
    low.assign(size(), 0);
    size_t *itr = new size_t[size()];
    bool *const used = new bool[size()];
    for (size_t v{}, c{}; v != size(); ++v) affix(v, c, itr, used + size());
    delete[] itr;
    delete[] used;
    for (auto &e : low) e += comp_cnt;
    reverse(begin(dag), end(dag));
    for (auto &arcs : dag)
      for (auto &to : arcs) to += comp_cnt;
  }

  size_t affix(size_t src, size_t &c, size_t *&itr, bool *used) {
    if (low[src]) return low[src];
    size_t idx = ++c;
    low[src] = idx;
    *itr++ = src;
    for (size_t dst : graph[src])
      low[src] = std::min(low[src], affix(dst, c, itr, used));
    if (low[src] == idx) {
      ++comp_cnt;
      used[-comp_cnt] = true;
      dag.emplace_back(0);
      auto srcp = itr;
      do {
        low[*--srcp] = -comp_cnt;
      } while (*srcp != src);
      while (itr != srcp) {
        auto now = *--itr;
        for (auto to : graph[now]) {
          if (!used[(int)low[to]]) {
            dag.back().emplace_back(low[to]);
            used[(int)low[to]] = true;
          }
        }
      }
      for (int c : dag.back()) used[c] = false;
      used[-comp_cnt] = false;
      return idx;
    }
    return low[src];
  }
};  // class strongly_connected_components
#line 108 "other/l2.cpp"

struct workspace::solver {
  solver() {
    // start here!
    int n, m;
    cin >> n >> m;
    Dinic<int> dinic(n + 2);
    strongly_connected_components scc(n);
    for (int i = 0; i < m; i++) {
      int a, b;
      cin >> a >> b;
      --a, --b;
      scc.add_edge(a, b);
      dinic.add_edge(a, b, 1);
    }

    const auto &dag = scc.shrinked_dag();
    const int cn = dag.size();
    vector<int> ind(cn), oud(cn);
    int src = -1, dst = -1;
    for (int i = 0; i < cn; i++) {
      if (dag[i].empty()) {
        if (~dst) {
          cout << -1 << eol;
          return;
        }
        dst = i;
      }
      for (int j : dag[i]) ind[j]++;
    }
    for (int i = 0; i < cn; i++) {
      if (!ind[i]) {
        if (~src) {
          cout << -1 << eol;
          return;
        }
        src = i;
      }
    }

    if (scc.count() == 1) {
      cout << "0\n";
      return;
    }

    const int fsrc = n + 1, fdst = n;
    for (int i = 0; i < n; i++) {
      if (scc[i] == src) {
        dinic.add_edge(fsrc, i, 2);
      } else if (scc[i] == dst) {
        dinic.add_edge(i, fdst, 2);
      }
    }

    if (dinic.max_flow(fsrc, fdst) < 2) {
      cout << "-1\n";
    } else {
      cout << dinic.ans - 2 << eol;
    }
  }
};
accuracy: 1
time_ms: 50
memory_kb: 34532
final_rank: 2

code_snippet: #include <bits/stdc++.h>

using namespace std;

// arg : S, state : T, ret : U
// void pre(int id, S &arg, T &state)
// pair<int, S> in(int id, int prechild, U ret, S &arg, T &state)
// U post(int id, S &arg, T &state)
template <typename S, typename T, typename U>
U non_rec_dfs(int n, int start, S start_arg, function<void(int, S &, T &)> pre,
              function<pair<int, S>(int, int, U, S &, T &)> in,
              function<U(int, S &, T &)> post) {
    stack<pair<int, int>> st;
    vector<int> prech(n, -1);
    vector<S> arg(n);
    vector<T> state(n);
    vector<U> ret(n);
    st.emplace(start, 0);
    arg[start] = start_arg;
    while (!st.empty()) {
        auto p = st.top();
        int now = p.first;
        int mode = p.second;
        st.pop();
        if (mode == 0) {
            pre(now, arg[now], state[now]);
            st.emplace(now, 1);
        } else if (mode == 1) {
            pair<int, S> call =
                in(now, prech[now], ret[prech[now]], arg[now], state[now]);
            int nxt = call.first;
            arg[nxt] = call.second;
            if (nxt != -1) {
                prech[now] = nxt;
                st.emplace(now, 1);
                st.emplace(nxt, 0);
            } else {
                st.emplace(now, 2);
            }
        } else {
            ret[now] = post(now, arg[now], state[now]);
        }
    }
    return ret[start];
}

int n, m;
vector<vector<int>> e, re;
vector<int> num;

void assign(vector<vector<int>> &edge) {
    struct sta {
        int idx;
    };
    num = vector<int>(n, -2);
    int tmp = 0;
    for (int i = 0; i < n; i++) {
        if (num[i] == -2) {
            tmp = non_rec_dfs<int, sta, int>(
                n, i, tmp,
                [&](int x, int &arg, sta &state) {
                    num[x] = -1;
                    state.idx = 0;
                    return;
                },
                [&](int x, int prech, int ret, int &arg, sta &state) {
                    if (prech != -1) arg = ret;
                    for (; state.idx < edge[x].size(); state.idx++) {
                        if (num[edge[x][state.idx]] == -2)
                            return pair<int, int>(edge[x][state.idx++], arg);
                    }
                    return pair<int, int>(-1, 0);
                },
                [&](int x, int &arg, sta &state) {
                    num[x] = arg;
                    return arg + 1;
                });
        }
    }
}

int main() {
    cin >> n >> m;
    e = re = vector<vector<int>>(n);
    for (int i = 0; i < m; i++) {
        int u, v;
        cin >> u >> v;
        u--, v--;
        e[u].push_back(v);
        re[v].push_back(u);
    }

    vector<int> d(n, -1);

    assign(e);
    vector<int> v(n);
    iota(v.begin(), v.end(), 0);
    sort(v.begin(), v.end(),
         [&](const int &l, const int &r) { return num[l] > num[r]; });
    queue<int> q, bfs;
    int start = v[0];
    d[v[0]] = 0;
    q.push(v[0]);
    bfs.push(v[0]);
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        for (auto x : re[now]) {
            if (d[x] != -1) continue;
            d[x] = 0;
            q.push(x);
            bfs.push(x);
        }
    }

    if (bfs.size() == n) {
        cout << 0 << endl;
        return 0;
    }

    assign(re);
    sort(v.begin(), v.end(),
         [&](const int &l, const int &r) { return num[l] > num[r]; });
    d[v[0]] = -2;
    q.push(v[0]);
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        for (auto x : e[now]) {
            if (d[x] != -1) continue;
            d[x] = -2;
            q.push(x);
        }
    }

    vector<int> par(n, -1);
    int g = -1;
    while (!bfs.empty()) {
        int now = bfs.front();
        bfs.pop();
        for (auto x : e[now]) {
            if (d[x] >= 0) continue;
            par[x] = now;
            if (d[x] == -2) {
                d[x] = d[now] + 1;
                g = x;
                goto found;
            }
            d[x] = d[now] + 1;
            bfs.push(x);
        }
    }

    cout << -1 << endl;
    return 0;

found:;
    int ans = d[g];
    set<pair<int, int>> st;
    while (par[g] != -1) {
        st.emplace(par[g], g);
        g = par[g];
    }

    vector<vector<int>> ne, nre;
    ne = nre = vector<vector<int>>(n);
    for (int u = 0; u < n; u++) {
        for (auto &v : e[u]) {
            if (st.find({u, v}) == st.end()) {
                ne[u].push_back(v);
                nre[v].push_back(u);
            } else {
                ne[v].push_back(u);
                nre[u].push_back(v);
            }
        }
    }

    assign(ne);
    sort(v.begin(), v.end(),
         [&](const int &l, const int &r) { return num[l] > num[r]; });
    int count = 1;
    d = vector<int>(n, false);
    d[v[0]] = true;
    q.push(v[0]);
    while (!q.empty()) {
        int now = q.front();
        q.pop();
        for (auto x : nre[now]) {
            if (d[x]) continue;
            count++;
            d[x] = true;
            q.push(x);
        }
    }

    if (count == n)
        cout << ans << endl;
    else
        cout << -1 << endl;

    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 31084
final_rank: 9

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;
// const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

template< typename T = int >
struct Edge {
  int from, to;
  T cost;
  int idx;

  Edge() = default;

  Edge(int from, int to, T cost = 1, int idx = -1) : from(from), to(to), cost(cost), idx(idx) {}

  operator int() const { return to; }
};

template< typename T = int >
struct Graph {
  vector< vector< Edge< T > > > g;
  int es;

  Graph() = default;

  explicit Graph(int n) : g(n), es(0) {}

  size_t size() const {
    return g.size();
  }

  void add_directed_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es++);
  }

  void add_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es);
    g[to].emplace_back(to, from, cost, es++);
  }

  void read(int M, int padding = -1, bool weighted = false, bool directed = false) {
    for(int i = 0; i < M; i++) {
      int a, b;
      cin >> a >> b;
      a += padding;
      b += padding;
      T c = T(1);
      if(weighted) cin >> c;
      if(directed) add_directed_edge(a, b, c);
      else add_edge(a, b, c);
    }
  }
};

template< typename T = int >
using Edges = vector< Edge< T > >;

/**
 * @brief Strongly-Connected-Components(強連結成分分解)
 */
template< typename T = int >
struct StronglyConnectedComponents : Graph< T > {
public:
  using Graph< T >::Graph;
  using Graph< T >::g;
  vector< int > comp;
  Graph< T > dag;
  vector< vector< int > > group;

  void build() {
    rg = Graph< T >(g.size());
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        rg.add_directed_edge(e.to, e.from, e.cost);
      }
    }
    comp.assign(g.size(), -1);
    used.assign(g.size(), 0);
    for(int i = 0; i < g.size(); i++) dfs(i);
    reverse(begin(order), end(order));
    int ptr = 0;
    for(int i : order) if(comp[i] == -1) rdfs(i, ptr), ptr++;
    dag = Graph< T >(ptr);
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        int x = comp[e.from], y = comp[e.to];
        if(x == y) continue;
        dag.add_directed_edge(x, y, e.cost);
      }
    }
    group.resize(ptr);
    for(int i = 0; i < g.size(); i++) {
      group[comp[i]].emplace_back(i);
    }
  }

  int operator[](int k) const {
    return comp[k];
  }

private:
  vector< int > order, used;
  Graph< T > rg;

  void dfs(int idx) {
    if(exchange(used[idx], true)) return;
    for(auto &to : g[idx]) dfs(to);
    order.push_back(idx);
  }

  void rdfs(int idx, int cnt) {
    if(comp[idx] != -1) return;
    comp[idx] = cnt;
    for(auto &to : rg.g[idx]) rdfs(to, cnt);
  }
};


/**
 * @brief Ford-Fulkerson(最大流)
 * @docs docs/ford-fulkerson.md
 */
template< typename flow_t >
struct FordFulkerson {
  struct edge {
    int to;
    flow_t cap;
    int rev;
    bool isrev;
    int idx;
  };

  vector< vector< edge > > graph;
  vector< int > used;
  const flow_t INF;
  int timestamp;

  explicit FordFulkerson(int V) : INF(numeric_limits< flow_t >::max()), graph(V), used(V, -1), timestamp(0) {}

  void add_edge(int from, int to, flow_t cap, int idx = -1) {
    graph[from].emplace_back((edge) {to, cap, (int) graph[to].size(), false, idx});
    graph[to].emplace_back((edge) {from, 0, (int) graph[from].size() - 1, true, idx});
  }

  flow_t find_augment_path(int idx, const int t, flow_t flow) {
    if(idx == t) return flow;
    used[idx] = timestamp;
    for(auto &e : graph[idx]) {
      if(e.cap > 0 && used[e.to] != timestamp) {
        flow_t d = find_augment_path(e.to, t, min(flow, e.cap));
        if(d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  flow_t max_flow(int s, int t) {
    flow_t flow = 0;
    for(flow_t f; (f = find_augment_path(s, t, INF)) > 0; timestamp++) {
      flow += f;
      if(flow >= 2) break;
    }
    return flow;
  }

  void output() {
    for(int i = 0; i < graph.size(); i++) {
      for(auto &e : graph[i]) {
        if(e.isrev) continue;
        auto &rev_e = graph[e.to][e.rev];
        cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
      }
    }
  }
};

/**
 * @brief Dijkstra(単一始点最短路)
 * @docs docs/dijkstra.md
 */
template< typename T >
struct ShortestPath {
  vector< T > dist;
  vector< int > from, id;
};

int main() {
  int N, M;
  cin >> N >> M;
  vector< int > A(M), B(M);
  Graph<> rg(N);
  StronglyConnectedComponents<> scc(N);
  for(int i = 0; i < M; i++) {
    cin >> A[i] >> B[i];
    --A[i], --B[i];
    scc.add_directed_edge(A[i], B[i]);
    rg.add_directed_edge(B[i], A[i]);
  }
  scc.build();
  if(scc.dag.size() == 1) {
    cout << 0 << "\n";
    exit(0);
  }
  vector< int > in(N), out(N);
  for(int i = 0; i < scc.dag.size(); i++) {
    if(scc.dag.g[i].size()) {
      in[i] = true;
    }
    for(auto &t : scc.dag.g[i]) {
      out[t] = true;
    }
  }

  vector< int > latte, malta;
  for(int i = 0; i < scc.dag.size(); i++) {
    if(!in[i]) {
      latte.emplace_back(i);
    }
    if(!out[i]) {
      malta.emplace_back(i);
    }
  }
  if(latte.size() != 1 && malta.size() != 1) {
    cout << -1 << "\n";
    exit(0);
  }


  FordFulkerson< int > flow(N + 2);
  for(int i = 0; i < M; i++) {
    flow.add_edge(A[i], B[i], 1);
  }
  for(auto &p : scc.group[malta[0]]) {
    flow.add_edge(N, p, inf);
  }
  for(auto &p : scc.group[latte[0]]) {
    flow.add_edge(p, N + 1, inf);
  }
  if(flow.max_flow(N, N + 1) <= 1) {
    cout << "-1\n";
    exit(0);
  }


  using T = int;
  const auto INF = numeric_limits< T >::max();
  vector< T > dist(scc.size(), INF);
  vector< int > from(scc.size(), -1), id(scc.size(), -1);
  using Pi = pair< T, int >;
  priority_queue< Pi, vector< Pi >, greater<> > que;
  for(auto &p : scc.group[latte[0]]) {
    dist[p] = 0;
    que.emplace(0, p);
  }
  while(!que.empty()) {
    T cost;
    int idx;
    tie(cost, idx) = que.top();
    que.pop();
    if(dist[idx] < cost) continue;
    for(auto &e : rg.g[idx]) {
      auto next_cost = cost + e.cost;
      if(dist[e.to] <= next_cost) continue;
      dist[e.to] = next_cost;
      from[e.to] = idx;
      id[e.to] = e.idx;
      que.emplace(dist[e.to], e.to);
    }
  }
  int ans = inf;
  for(auto &p : scc.group[malta[0]]) {
    chmin(ans, dist[p]);
  }
  if(ans >= inf) ans = -1;
  cout << ans << "\n";
}
accuracy: 1
time_ms: 70
memory_kb: 46852
final_rank: 6

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;
// const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

template< typename T = int >
struct Edge {
  int from, to;
  T cost;
  int idx;

  Edge() = default;

  Edge(int from, int to, T cost = 1, int idx = -1) : from(from), to(to), cost(cost), idx(idx) {}

  operator int() const { return to; }
};

template< typename T = int >
struct Graph {
  vector< vector< Edge< T > > > g;
  int es;

  Graph() = default;

  explicit Graph(int n) : g(n), es(0) {}

  size_t size() const {
    return g.size();
  }

  void add_directed_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es++);
  }

  void add_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es);
    g[to].emplace_back(to, from, cost, es++);
  }

  void read(int M, int padding = -1, bool weighted = false, bool directed = false) {
    for(int i = 0; i < M; i++) {
      int a, b;
      cin >> a >> b;
      a += padding;
      b += padding;
      T c = T(1);
      if(weighted) cin >> c;
      if(directed) add_directed_edge(a, b, c);
      else add_edge(a, b, c);
    }
  }
};

template< typename T = int >
using Edges = vector< Edge< T > >;

/**
 * @brief Strongly-Connected-Components(強連結成分分解)
 */
template< typename T = int >
struct StronglyConnectedComponents : Graph< T > {
public:
  using Graph< T >::Graph;
  using Graph< T >::g;
  vector< int > comp;
  Graph< T > dag;
  vector< vector< int > > group;

  void build() {
    rg = Graph< T >(g.size());
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        rg.add_directed_edge(e.to, e.from, e.cost);
      }
    }
    comp.assign(g.size(), -1);
    used.assign(g.size(), 0);
    for(int i = 0; i < g.size(); i++) dfs(i);
    reverse(begin(order), end(order));
    int ptr = 0;
    for(int i : order) if(comp[i] == -1) rdfs(i, ptr), ptr++;
    dag = Graph< T >(ptr);
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        int x = comp[e.from], y = comp[e.to];
        if(x == y) continue;
        dag.add_directed_edge(x, y, e.cost);
      }
    }
    group.resize(ptr);
    for(int i = 0; i < g.size(); i++) {
      group[comp[i]].emplace_back(i);
    }
  }

  int operator[](int k) const {
    return comp[k];
  }

private:
  vector< int > order, used;
  Graph< T > rg;

  void dfs(int idx) {
    if(exchange(used[idx], true)) return;
    for(auto &to : g[idx]) dfs(to);
    order.push_back(idx);
  }

  void rdfs(int idx, int cnt) {
    if(comp[idx] != -1) return;
    comp[idx] = cnt;
    for(auto &to : rg.g[idx]) rdfs(to, cnt);
  }
};


/**
 * @brief Ford-Fulkerson(最大流)
 * @docs docs/ford-fulkerson.md
 */
template< typename flow_t >
struct FordFulkerson {
  struct edge {
    int to;
    flow_t cap;
    int rev;
    bool isrev;
    int idx;
  };

  vector< vector< edge > > graph;
  vector< int > used;
  const flow_t INF;
  int timestamp;

  explicit FordFulkerson(int V) : INF(numeric_limits< flow_t >::max()), graph(V), used(V, -1), timestamp(0) {}

  void add_edge(int from, int to, flow_t cap, int idx = -1) {
    graph[from].emplace_back((edge) {to, cap, (int) graph[to].size(), false, idx});
    graph[to].emplace_back((edge) {from, 0, (int) graph[from].size() - 1, true, idx});
  }

  flow_t find_augment_path(int idx, const int t, flow_t flow) {
    if(idx == t) return flow;
    used[idx] = timestamp;
    for(auto &e : graph[idx]) {
      if(e.cap > 0 && used[e.to] != timestamp) {
        flow_t d = find_augment_path(e.to, t, min(flow, e.cap));
        if(d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  flow_t max_flow(int s, int t) {
    flow_t flow = 0;
    for(flow_t f; (f = find_augment_path(s, t, INF)) > 0; timestamp++) {
      flow += f;
    }
    return flow;
  }

  void output() {
    for(int i = 0; i < graph.size(); i++) {
      for(auto &e : graph[i]) {
        if(e.isrev) continue;
        auto &rev_e = graph[e.to][e.rev];
        cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
      }
    }
  }
};

/**
 * @brief Dijkstra(単一始点最短路)
 * @docs docs/dijkstra.md
 */
template< typename T >
struct ShortestPath {
  vector< T > dist;
  vector< int > from, id;
};

int main() {
  int N, M;
  cin >> N >> M;
  vector< int > A(M), B(M);
  Graph<> rg(N);
  StronglyConnectedComponents<> scc(N);
  for(int i = 0; i < M; i++) {
    cin >> A[i] >> B[i];
    --A[i], --B[i];
    scc.add_directed_edge(A[i], B[i]);
    rg.add_directed_edge(B[i], A[i]);
  }
  scc.build();
  if(scc.dag.size() == 1) {
    cout << 0 << "\n";
    exit(0);
  }
  vector< int > in(N), out(N);
  for(int i = 0; i < scc.dag.size(); i++) {
    if(scc.dag.g[i].size()) {
      in[i] = true;
    }
    for(auto &t : scc.dag.g[i]) {
      out[t] = true;
    }
  }

  vector< int > latte, malta;
  for(int i = 0; i < scc.dag.size(); i++) {
    if(!in[i]) {
      latte.emplace_back(i);
    }
    if(!out[i]) {
      malta.emplace_back(i);
    }
  }
  if(latte.size() != 1 && malta.size() != 1) {
    cout << -1 << "\n";
    exit(0);
  }


  FordFulkerson< int > flow(scc.dag.size());
  for(int i = 0; i < scc.dag.size(); i++) {
    for(auto &p : scc.dag.g[i]) {
      flow.add_edge(i, p, 1);
    }
  }
  if(flow.max_flow(malta[0], latte[0]) <= 1) {
    cout << "-1\n";
    exit(0);
  }


  using T = int;
  const auto INF = numeric_limits< T >::max();
  vector< T > dist(scc.size(), INF);
  vector< int > from(scc.size(), -1), id(scc.size(), -1);
  using Pi = pair< T, int >;
  priority_queue< Pi, vector< Pi >, greater<> > que;
  for(auto &p : scc.group[latte[0]]) {
    dist[p] = 0;
    que.emplace(0, p);
  }
  while(!que.empty()) {
    T cost;
    int idx;
    tie(cost, idx) = que.top();
    que.pop();
    if(dist[idx] < cost) continue;
    for(auto &e : rg.g[idx]) {
      auto next_cost = cost + e.cost;
      if(dist[e.to] <= next_cost) continue;
      dist[e.to] = next_cost;
      from[e.to] = idx;
      id[e.to] = e.idx;
      que.emplace(dist[e.to], e.to);
    }
  }
  int ans = inf;
  for(auto &p : scc.group[malta[0]]) {
    chmin(ans, dist[p]);
  }
  cout << ans << "\n";
}
accuracy: 0.35135135135135137
time_ms: 30
memory_kb: 26864
final_rank: 18

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;
// const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

template< typename T = int >
struct Edge {
  int from, to;
  T cost;
  int idx;

  Edge() = default;

  Edge(int from, int to, T cost = 1, int idx = -1) : from(from), to(to), cost(cost), idx(idx) {}

  operator int() const { return to; }
};

template< typename T = int >
struct Graph {
  vector< vector< Edge< T > > > g;
  int es;

  Graph() = default;

  explicit Graph(int n) : g(n), es(0) {}

  size_t size() const {
    return g.size();
  }

  void add_directed_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es++);
  }

  void add_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es);
    g[to].emplace_back(to, from, cost, es++);
  }

  void read(int M, int padding = -1, bool weighted = false, bool directed = false) {
    for(int i = 0; i < M; i++) {
      int a, b;
      cin >> a >> b;
      a += padding;
      b += padding;
      T c = T(1);
      if(weighted) cin >> c;
      if(directed) add_directed_edge(a, b, c);
      else add_edge(a, b, c);
    }
  }
};

template< typename T = int >
using Edges = vector< Edge< T > >;

/**
 * @brief Strongly-Connected-Components(強連結成分分解)
 */
template< typename T = int >
struct StronglyConnectedComponents : Graph< T > {
public:
  using Graph< T >::Graph;
  using Graph< T >::g;
  vector< int > comp;
  Graph< T > dag;
  vector< vector< int > > group;

  void build() {
    rg = Graph< T >(g.size());
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        rg.add_directed_edge(e.to, e.from, e.cost);
      }
    }
    comp.assign(g.size(), -1);
    used.assign(g.size(), 0);
    for(int i = 0; i < g.size(); i++) dfs(i);
    reverse(begin(order), end(order));
    int ptr = 0;
    for(int i : order) if(comp[i] == -1) rdfs(i, ptr), ptr++;
    dag = Graph< T >(ptr);
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        int x = comp[e.from], y = comp[e.to];
        if(x == y) continue;
        dag.add_directed_edge(x, y, e.cost);
      }
    }
    group.resize(ptr);
    for(int i = 0; i < g.size(); i++) {
      group[comp[i]].emplace_back(i);
    }
  }

  int operator[](int k) const {
    return comp[k];
  }

private:
  vector< int > order, used;
  Graph< T > rg;

  void dfs(int idx) {
    if(exchange(used[idx], true)) return;
    for(auto &to : g[idx]) dfs(to);
    order.push_back(idx);
  }

  void rdfs(int idx, int cnt) {
    if(comp[idx] != -1) return;
    comp[idx] = cnt;
    for(auto &to : rg.g[idx]) rdfs(to, cnt);
  }
};


/**
 * @brief Ford-Fulkerson(最大流)
 * @docs docs/ford-fulkerson.md
 */
template< typename flow_t >
struct FordFulkerson {
  struct edge {
    int to;
    flow_t cap;
    int rev;
    bool isrev;
    int idx;
  };

  vector< vector< edge > > graph;
  vector< int > used;
  const flow_t INF;
  int timestamp;

  explicit FordFulkerson(int V) : INF(numeric_limits< flow_t >::max()), graph(V), used(V, -1), timestamp(0) {}

  void add_edge(int from, int to, flow_t cap, int idx = -1) {
    graph[from].emplace_back((edge) {to, cap, (int) graph[to].size(), false, idx});
    graph[to].emplace_back((edge) {from, 0, (int) graph[from].size() - 1, true, idx});
  }

  flow_t find_augment_path(int idx, const int t, flow_t flow) {
    if(idx == t) return flow;
    used[idx] = timestamp;
    for(auto &e : graph[idx]) {
      if(e.cap > 0 && used[e.to] != timestamp) {
        flow_t d = find_augment_path(e.to, t, min(flow, e.cap));
        if(d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  flow_t max_flow(int s, int t) {
    flow_t flow = 0;
    for(flow_t f; (f = find_augment_path(s, t, INF)) > 0; timestamp++) {
      flow += f;
    }
    return flow;
  }

  void output() {
    for(int i = 0; i < graph.size(); i++) {
      for(auto &e : graph[i]) {
        if(e.isrev) continue;
        auto &rev_e = graph[e.to][e.rev];
        cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
      }
    }
  }
};

/**
 * @brief Dijkstra(単一始点最短路)
 * @docs docs/dijkstra.md
 */
template< typename T >
struct ShortestPath {
  vector< T > dist;
  vector< int > from, id;
};

int main() {
  int N, M;
  cin >> N >> M;
  vector< int > A(M), B(M);
  Graph<> rg(N);
  StronglyConnectedComponents<> scc(N);
  for(int i = 0; i < M; i++) {
    cin >> A[i] >> B[i];
    --A[i], --B[i];
    scc.add_directed_edge(A[i], B[i]);
    rg.add_directed_edge(B[i], A[i]);
  }
  scc.build();
  if(scc.dag.size() == 1) {
    cout << 0 << "\n";
    exit(0);
  }
  vector< int > in(N), out(N);
  for(int i = 0; i < scc.dag.size(); i++) {
    if(scc.dag.g[i].size()) {
      in[i] = true;
    }
    for(auto &t : scc.dag.g[i]) {
      out[t] = true;
    }
  }

  vector< int > latte, malta;
  for(int i = 0; i < scc.size(); i++) {
    if(!in[i]) {
      latte.emplace_back(i);
    }
    if(!out[i]) {
      malta.emplace_back(i);
    }
  }
  if(latte.size() != 1 && malta.size() != 1) {
    cout << -1 << "\n";
    exit(0);
  }


  FordFulkerson< int > flow(scc.size());
  for(int i = 0; i < scc.size(); i++) {
    for(auto &p : scc.dag.g[i]) {
      flow.add_edge(i, p, 1);
    }
  }
  if(flow.max_flow(malta[0], latte[0]) <= 1) {
    cout << "-1\n";
    exit(0);
  }


  using T = int;
  const auto INF = numeric_limits< T >::max();
  vector< T > dist(scc.size(), INF);
  vector< int > from(scc.size(), -1), id(scc.size(), -1);
  using Pi = pair< T, int >;
  priority_queue< Pi, vector< Pi >, greater<> > que;
  for(auto &p : scc.group[latte[0]]) {
    dist[p] = 0;
    que.emplace(0, p);
  }
  while(!que.empty()) {
    T cost;
    int idx;
    tie(cost, idx) = que.top();
    que.pop();
    if(dist[idx] < cost) continue;
    for(auto &e : rg.g[idx]) {
      auto next_cost = cost + e.cost;
      if(dist[e.to] <= next_cost) continue;
      dist[e.to] = next_cost;
      from[e.to] = idx;
      id[e.to] = e.idx;
      que.emplace(dist[e.to], e.to);
    }
  }
  int ans = inf;
  for(auto &p : scc.group[malta[0]]) {
    chmin(ans, dist[p]);
  }
  cout << ans << "\n";
}
accuracy: 0.5
time_ms: 40
memory_kb: 30020
final_rank: 12

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;
// const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

template< typename T = int >
struct Edge {
  int from, to;
  T cost;
  int idx;

  Edge() = default;

  Edge(int from, int to, T cost = 1, int idx = -1) : from(from), to(to), cost(cost), idx(idx) {}

  operator int() const { return to; }
};

template< typename T = int >
struct Graph {
  vector< vector< Edge< T > > > g;
  int es;

  Graph() = default;

  explicit Graph(int n) : g(n), es(0) {}

  size_t size() const {
    return g.size();
  }

  void add_directed_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es++);
  }

  void add_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es);
    g[to].emplace_back(to, from, cost, es++);
  }

  void read(int M, int padding = -1, bool weighted = false, bool directed = false) {
    for(int i = 0; i < M; i++) {
      int a, b;
      cin >> a >> b;
      a += padding;
      b += padding;
      T c = T(1);
      if(weighted) cin >> c;
      if(directed) add_directed_edge(a, b, c);
      else add_edge(a, b, c);
    }
  }
};

template< typename T = int >
using Edges = vector< Edge< T > >;

/**
 * @brief Strongly-Connected-Components(強連結成分分解)
 */
template< typename T = int >
struct StronglyConnectedComponents : Graph< T > {
public:
  using Graph< T >::Graph;
  using Graph< T >::g;
  vector< int > comp;
  Graph< T > dag;
  vector< vector< int > > group;

  void build() {
    rg = Graph< T >(g.size());
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        rg.add_directed_edge(e.to, e.from, e.cost);
      }
    }
    comp.assign(g.size(), -1);
    used.assign(g.size(), 0);
    for(int i = 0; i < g.size(); i++) dfs(i);
    reverse(begin(order), end(order));
    int ptr = 0;
    for(int i : order) if(comp[i] == -1) rdfs(i, ptr), ptr++;
    dag = Graph< T >(ptr);
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        int x = comp[e.from], y = comp[e.to];
        if(x == y) continue;
        dag.add_directed_edge(x, y, e.cost);
      }
    }
    group.resize(ptr);
    for(int i = 0; i < g.size(); i++) {
      group[comp[i]].emplace_back(i);
    }
  }

  int operator[](int k) const {
    return comp[k];
  }

private:
  vector< int > order, used;
  Graph< T > rg;

  void dfs(int idx) {
    if(exchange(used[idx], true)) return;
    for(auto &to : g[idx]) dfs(to);
    order.push_back(idx);
  }

  void rdfs(int idx, int cnt) {
    if(comp[idx] != -1) return;
    comp[idx] = cnt;
    for(auto &to : rg.g[idx]) rdfs(to, cnt);
  }
};


/**
 * @brief Ford-Fulkerson(最大流)
 * @docs docs/ford-fulkerson.md
 */
template< typename flow_t >
struct FordFulkerson {
  struct edge {
    int to;
    flow_t cap;
    int rev;
    bool isrev;
    int idx;
  };

  vector< vector< edge > > graph;
  vector< int > used;
  const flow_t INF;
  int timestamp;

  explicit FordFulkerson(int V) : INF(numeric_limits< flow_t >::max()), graph(V), used(V, -1), timestamp(0) {}

  void add_edge(int from, int to, flow_t cap, int idx = -1) {
    graph[from].emplace_back((edge) {to, cap, (int) graph[to].size(), false, idx});
    graph[to].emplace_back((edge) {from, 0, (int) graph[from].size() - 1, true, idx});
  }

  flow_t find_augment_path(int idx, const int t, flow_t flow) {
    if(idx == t) return flow;
    used[idx] = timestamp;
    for(auto &e : graph[idx]) {
      if(e.cap > 0 && used[e.to] != timestamp) {
        flow_t d = find_augment_path(e.to, t, min(flow, e.cap));
        if(d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  flow_t max_flow(int s, int t) {
    flow_t flow = 0;
    for(flow_t f; (f = find_augment_path(s, t, INF)) > 0; timestamp++) {
      flow += f;
      if(flow >= 2) break;
    }
    return flow;
  }

  void output() {
    for(int i = 0; i < graph.size(); i++) {
      for(auto &e : graph[i]) {
        if(e.isrev) continue;
        auto &rev_e = graph[e.to][e.rev];
        cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
      }
    }
  }
};

/**
 * @brief Dijkstra(単一始点最短路)
 * @docs docs/dijkstra.md
 */
template< typename T >
struct ShortestPath {
  vector< T > dist;
  vector< int > from, id;
};

int main() {
  int N, M;
  cin >> N >> M;
  vector< int > A(M), B(M);
  Graph<> rg(N);
  StronglyConnectedComponents<> scc(N);
  for(int i = 0; i < M; i++) {
    cin >> A[i] >> B[i];
    --A[i], --B[i];
    scc.add_directed_edge(A[i], B[i]);
    rg.add_directed_edge(B[i], A[i]);
  }
  scc.build();
  if(scc.dag.size() == 1) {
    cout << 0 << "\n";
    exit(0);
  }
  vector< int > in(N), out(N);
  for(int i = 0; i < scc.dag.size(); i++) {
    if(scc.dag.g[i].size()) {
      in[i] = true;
    }
    for(auto &t : scc.dag.g[i]) {
      out[t] = true;
    }
  }

  vector< int > latte, malta;
  for(int i = 0; i < N; i++) {
    if(!in[i]) {
      latte.emplace_back(i);
    }
    if(!out[i]) {
      malta.emplace_back(i);
    }
  }
  if(latte.size() != 1 && malta.size() != 1) {
    cout << -1 << "\n";
    exit(0);
  }


  FordFulkerson< int > flow(N + 2);
  for(int i = 0; i < M; i++) {
    flow.add_edge(A[i], B[i], 1);
  }
  for(auto &p : scc.group[malta[0]]) {
    flow.add_edge(N, p, inf);
  }
  for(auto &p : scc.group[latte[0]]) {
    flow.add_edge(p, N + 1, inf);
  }
  if(flow.max_flow(N, N + 1) <= 1) {
    cout << "-1\n";
    exit(0);
  }


  using T = int;
  const auto INF = numeric_limits< T >::max();
  vector< T > dist(scc.size(), INF);
  vector< int > from(scc.size(), -1), id(scc.size(), -1);
  using Pi = pair< T, int >;
  priority_queue< Pi, vector< Pi >, greater<> > que;
  for(auto &p : scc.group[latte[0]]) {
    dist[p] = 0;
    que.emplace(0, p);
  }
  while(!que.empty()) {
    T cost;
    int idx;
    tie(cost, idx) = que.top();
    que.pop();
    if(dist[idx] < cost) continue;
    for(auto &e : rg.g[idx]) {
      auto next_cost = cost + e.cost;
      if(dist[e.to] <= next_cost) continue;
      dist[e.to] = next_cost;
      from[e.to] = idx;
      id[e.to] = e.idx;
      que.emplace(dist[e.to], e.to);
    }
  }
  int ans = inf;
  for(auto &p : scc.group[malta[0]]) {
    chmin(ans, dist[p]);
  }
  if(ans >= inf) ans = -1;
  cout << ans << "\n";
}
accuracy: 0.5
time_ms: 50
memory_kb: 30508
final_rank: 15

code_snippet: #include <bits/stdc++.h>

// #include <atcoder/all>

using namespace std;
// using namespace atcoder;
 
#define DEBUG(x) cerr<<#x<<": "<<x<<endl;
#define DEBUG_VEC(v) cerr<<#v<<":";for(int i=0;i<v.size();i++) cerr<<" "<<v[i]; cerr<<endl;
#define DEBUG_MAT(v) cerr<<#v<<endl;for(int i=0;i<v.size();i++){for(int j=0;j<v[i].size();j++) {cerr<<v[i][j]<<" ";}cerr<<endl;}
typedef long long ll;
// #define int ll
 
#define vi vector<int>
#define vl vector<ll>
#define vii vector< vector<int> >
#define vll vector< vector<ll> >
#define vs vector<string>
#define pii pair<int,int>
#define pis pair<int,string>
#define psi pair<string,int>
#define pll pair<ll,ll>
template<class S, class T> pair<S, T> operator+(const pair<S, T> &s, const pair<S, T> &t) { return pair<S, T>(s.first + t.first, s.second + t.second); }
template<class S, class T> pair<S, T> operator-(const pair<S, T> &s, const pair<S, T> &t) { return pair<S, T>(s.first - t.first, s.second - t.second); }
template<class S, class T> ostream& operator<<(ostream& os, pair<S, T> p) { os << "(" << p.first << ", " << p.second << ")"; return os; }
#define X first
#define Y second
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define rrep(i,n) for(int i=(int)(n)-1;i>=0;i--)
#define rrep1(i,n) for(int i=(int)(n);i>0;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define in(x, a, b) (a <= x && x < b)
#define all(c) c.begin(),c.end()
template<class T> bool chmax(T &a, const T &b) { if (a<b) { a = b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a = b; return 1; } return 0; }
#define UNIQUE(v) v.erase(std::unique(v.begin(), v.end()), v.end());
const ll inf = 1000000001;
const ll INF = (ll)1e18 + 1;
const long double pi = 3.1415926535897932384626433832795028841971L;
#define Sp(p) cout<<setprecision(25)<< fixed<<p<<endl;
// int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
// int dx2[8] = { 1,1,0,-1,-1,-1,0,1 }, dy2[8] = { 0,1,1,1,0,-1,-1,-1 };
vi dx = {1, 0, -1, 0}, dy = {0, 1, 0, -1};
// vi dx2 = { 1,1,0,-1,-1,-1,0,1 }, dy2 = { 0,1,1,1,0,-1,-1,-1 };
#define fio() cin.tie(0); ios::sync_with_stdio(false);
// const ll MOD = 1000000007;
const ll MOD = 998244353;
// #define mp make_pair
//#define endl '\n'


namespace internal {

template <class E> struct csr {
    std::vector<int> start;
    std::vector<E> elist;
    csr(int n, const std::vector<std::pair<int, E>>& edges)
        : start(n + 1), elist(edges.size()) {
        for (auto e : edges) {
            start[e.first + 1]++;
        }
        for (int i = 1; i <= n; i++) {
            start[i] += start[i - 1];
        }
        auto counter = start;
        for (auto e : edges) {
            elist[counter[e.first]++] = e.second;
        }
    }
};

// Reference:
// R. Tarjan,
// Depth-First Search and Linear Graph Algorithms
struct scc_graph {
  public:
    scc_graph(int n) : _n(n) {}

    int num_vertices() { return _n; }

    void add_edge(int from, int to) { edges.push_back({from, {to}}); }

    // @return pair of (# of scc, scc id)
    std::pair<int, std::vector<int>> scc_ids() {
        auto g = csr<edge>(_n, edges);
        int now_ord = 0, group_num = 0;
        std::vector<int> visited, low(_n), ord(_n, -1), ids(_n);
        visited.reserve(_n);
        auto dfs = [&](auto self, int v) -> void {
            low[v] = ord[v] = now_ord++;
            visited.push_back(v);
            for (int i = g.start[v]; i < g.start[v + 1]; i++) {
                auto to = g.elist[i].to;
                if (ord[to] == -1) {
                    self(self, to);
                    low[v] = std::min(low[v], low[to]);
                } else {
                    low[v] = std::min(low[v], ord[to]);
                }
            }
            if (low[v] == ord[v]) {
                while (true) {
                    int u = visited.back();
                    visited.pop_back();
                    ord[u] = _n;
                    ids[u] = group_num;
                    if (u == v) break;
                }
                group_num++;
            }
        };
        for (int i = 0; i < _n; i++) {
            if (ord[i] == -1) dfs(dfs, i);
        }
        for (auto& x : ids) {
            x = group_num - 1 - x;
        }
        return {group_num, ids};
    }

    std::vector<std::vector<int>> scc() {
        auto ids = scc_ids();
        int group_num = ids.first;
        std::vector<int> counts(group_num);
        for (auto x : ids.second) counts[x]++;
        std::vector<std::vector<int>> groups(ids.first);
        for (int i = 0; i < group_num; i++) {
            groups[i].reserve(counts[i]);
        }
        for (int i = 0; i < _n; i++) {
            groups[ids.second[i]].push_back(i);
        }
        return groups;
    }

  private:
    int _n;
    struct edge {
        int to;
    };
    std::vector<std::pair<int, edge>> edges;
};

}  // namespace internal

struct scc_graph {
  public:
    scc_graph() : internal(0) {}
    scc_graph(int n) : internal(n) {}

    void add_edge(int from, int to) {
        int n = internal.num_vertices();
        assert(0 <= from && from < n);
        assert(0 <= to && to < n);
        internal.add_edge(from, to);
    }

    std::vector<std::vector<int>> scc() { return internal.scc(); }

  private:
    internal::scc_graph internal;
};

vi group;
int first_group, last_group;

// bool dfs(int now, int target, vector<vector<pii>>& G, set<int>& used_edges, vector<bool> visited) {
//     if (now == target) return true;
//     visited[now] = true;
//     for (pii temp: G[now]) {
//         int v = temp.first;
//         if (visited[v]) continue;
//         int edge_idx = temp.second;
//         if (used_edges.count(edge_idx)) continue;
//         used_edges.insert(edge_idx);
//         if (dfs(v, target, G, used_edges, visited)) return true;
//         used_edges.erase(edge_idx);
//     }
//     return false;
// }



// �ӂ�\���\���� {�s��A�e�ʁA�t��}
struct edge { int to; ll cap; int rev; };
#define V 101000
int s, t; //s��start, t��goal
vector< vector<edge> > G(V, vector<edge>());; //�O���t�̗אڃ��X�g�\��
vector<bool> used(V); //DEF�Œ��ׂ����̃t���O

					  //from����to�֌������e��cap�̕ӂ��O���t�ɒǉ�����
void add_edge(int from, int to, ll cap) {
	edge a;
	a.to = to; a.cap = cap; a.rev = G[to].size();
	G[from].push_back(a);
	a.to = from; a.cap = 0; a.rev = G[from].size() - 1;
	G[to].push_back(a);
}

ll dfs(int v, int t, ll f) {
	if (v == t) {
		return f;
	}
	used[v] = true;
	for (int i = 0; i < G[v].size(); i++) {
		edge &e = G[v][i];
		if (!used[e.to] && e.cap > 0) {
			ll d = dfs(e.to, t, min(f, e.cap));
			if (d > 0) {
				e.cap -= d;
				G[e.to][e.rev].cap += d;
				return d;
			}
		}
	}
	return 0;
}

ll max_flow(int s, int t) {
	ll flow = 0;
	while (true) {
		fill(used.begin(), used.end(), false);
		ll f = dfs(s, t, INF);
		if (f == 0) return flow;
		flow += f;
        if (flow >= 2) return flow;
	}
}


signed main() {
    fio();
    int n, m;
    cin >> n >> m;
    scc_graph scc(n);

    vii G(n);
    rep (i, m) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        G[u].push_back(v);
        scc.add_edge(u, v);
        add_edge(u, v, 1);
    }

    vii res = scc.scc();
    int k = res.size();
    if (k == 1) {
        cout << 0 << endl;
        return 0;
    }

    group.resize(n);
    rep (i, res.size()) {
        for (int u: res[i]) {
            group[u] = i;
        }
    }

    vii G2(k);
    vii rG2(k);
    rep (u, n) {
        for (int v: G[u]) {
            if (group[u] == group[v]) continue;
            G2[group[u]].push_back(group[v]);
            rG2[group[v]].push_back(group[u]);
            // add_edge(group[u], group[v], 1);
        }
    }
    // vector<vector<pii>> G3(k);
    // int edge_num = 0;
    // rep (u, k) {
    //     for (int v: G2[u]) {
    //         G3[u].push_back(pii(v, edge_num++));
    //     }
    // }

    rep (u, k) {
        sort(all(G2[u]));
        UNIQUE(G2[u]);
        sort(all(rG2[u]));
        UNIQUE(rG2[u]);
    }

    vi in0, out0;
    rep (i, k) {
        if (G2[i].size() == 0) {
            out0.push_back(i);
        }
        if (rG2[i].size() == 0) {
            in0.push_back(i);
        }
    }

    if (in0.size() > 1 or out0.size() > 1) {
        cout << -1 << endl;
        return 0;
    }

    first_group = in0[0];
    last_group = out0[0];
    // int F = max_flow(first_group, last_group);
    int s = n, t = n + 1;
    rep (i, n) {
        if (group[i] == first_group) add_edge(s, i, 2);
        if (group[i] == last_group) add_edge(i, t, 2);
    }
    int F = max_flow(s, t);
    if (F < 2) {
        cout << -1 << endl;
        return 0;
    }

    // set<int> used_edges;
    // DEBUG_MAT(res);
    // DEBUG_MAT(G3);
    // vector<bool> visited(k);
    // if (not dfs(first_group, last_group, G3, used_edges, visited)) {
    //     cout << -1 << endl;
    //     return 0;
    // }
    // fill(all(visited), false);
    // if (not dfs(first_group, last_group, G3, used_edges, visited)) {
    //     cout << -1 << endl;
    //     return 0;
    // }

    vi dist(n, inf);
    queue<int> qu;
    for (int u: res[first_group]) {
        dist[u] = 0;
        qu.push(u);
    }
    // DEBUG_VEC(dist);
    // DEBUG_MAT(G);    

    int ans = inf;
    while (qu.size()) {
        int u = qu.front();
        qu.pop();
        if (group[u] == last_group) {
            chmin(ans, dist[u]);
        }

        for (int v: G[u]) {
            if (dist[v] > dist[u] + 1) {
                dist[v] = dist[u] + 1;
                qu.push(v);
            }
        }
    }
    cout << ans << endl;
}
accuracy: 1
time_ms: 70
memory_kb: 41268
final_rank: 4

code_snippet: #include <bits/stdc++.h>

// #include <atcoder/all>

using namespace std;
// using namespace atcoder;
 
#define DEBUG(x) cerr<<#x<<": "<<x<<endl;
#define DEBUG_VEC(v) cerr<<#v<<":";for(int i=0;i<v.size();i++) cerr<<" "<<v[i]; cerr<<endl;
#define DEBUG_MAT(v) cerr<<#v<<endl;for(int i=0;i<v.size();i++){for(int j=0;j<v[i].size();j++) {cerr<<v[i][j]<<" ";}cerr<<endl;}
typedef long long ll;
// #define int ll
 
#define vi vector<int>
#define vl vector<ll>
#define vii vector< vector<int> >
#define vll vector< vector<ll> >
#define vs vector<string>
#define pii pair<int,int>
#define pis pair<int,string>
#define psi pair<string,int>
#define pll pair<ll,ll>
template<class S, class T> pair<S, T> operator+(const pair<S, T> &s, const pair<S, T> &t) { return pair<S, T>(s.first + t.first, s.second + t.second); }
template<class S, class T> pair<S, T> operator-(const pair<S, T> &s, const pair<S, T> &t) { return pair<S, T>(s.first - t.first, s.second - t.second); }
template<class S, class T> ostream& operator<<(ostream& os, pair<S, T> p) { os << "(" << p.first << ", " << p.second << ")"; return os; }
#define X first
#define Y second
#define rep(i,n) for(int i=0;i<(int)(n);i++)
#define rep1(i,n) for(int i=1;i<=(int)(n);i++)
#define rrep(i,n) for(int i=(int)(n)-1;i>=0;i--)
#define rrep1(i,n) for(int i=(int)(n);i>0;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define in(x, a, b) (a <= x && x < b)
#define all(c) c.begin(),c.end()
template<class T> bool chmax(T &a, const T &b) { if (a<b) { a = b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a = b; return 1; } return 0; }
#define UNIQUE(v) v.erase(std::unique(v.begin(), v.end()), v.end());
const ll inf = 1000000001;
const ll INF = (ll)1e18 + 1;
const long double pi = 3.1415926535897932384626433832795028841971L;
#define Sp(p) cout<<setprecision(25)<< fixed<<p<<endl;
// int dx[4] = {1, 0, -1, 0}, dy[4] = {0, 1, 0, -1};
// int dx2[8] = { 1,1,0,-1,-1,-1,0,1 }, dy2[8] = { 0,1,1,1,0,-1,-1,-1 };
vi dx = {1, 0, -1, 0}, dy = {0, 1, 0, -1};
// vi dx2 = { 1,1,0,-1,-1,-1,0,1 }, dy2 = { 0,1,1,1,0,-1,-1,-1 };
#define fio() cin.tie(0); ios::sync_with_stdio(false);
// const ll MOD = 1000000007;
const ll MOD = 998244353;
// #define mp make_pair
//#define endl '\n'


namespace internal {

template <class E> struct csr {
    std::vector<int> start;
    std::vector<E> elist;
    csr(int n, const std::vector<std::pair<int, E>>& edges)
        : start(n + 1), elist(edges.size()) {
        for (auto e : edges) {
            start[e.first + 1]++;
        }
        for (int i = 1; i <= n; i++) {
            start[i] += start[i - 1];
        }
        auto counter = start;
        for (auto e : edges) {
            elist[counter[e.first]++] = e.second;
        }
    }
};

// Reference:
// R. Tarjan,
// Depth-First Search and Linear Graph Algorithms
struct scc_graph {
  public:
    scc_graph(int n) : _n(n) {}

    int num_vertices() { return _n; }

    void add_edge(int from, int to) { edges.push_back({from, {to}}); }

    // @return pair of (# of scc, scc id)
    std::pair<int, std::vector<int>> scc_ids() {
        auto g = csr<edge>(_n, edges);
        int now_ord = 0, group_num = 0;
        std::vector<int> visited, low(_n), ord(_n, -1), ids(_n);
        visited.reserve(_n);
        auto dfs = [&](auto self, int v) -> void {
            low[v] = ord[v] = now_ord++;
            visited.push_back(v);
            for (int i = g.start[v]; i < g.start[v + 1]; i++) {
                auto to = g.elist[i].to;
                if (ord[to] == -1) {
                    self(self, to);
                    low[v] = std::min(low[v], low[to]);
                } else {
                    low[v] = std::min(low[v], ord[to]);
                }
            }
            if (low[v] == ord[v]) {
                while (true) {
                    int u = visited.back();
                    visited.pop_back();
                    ord[u] = _n;
                    ids[u] = group_num;
                    if (u == v) break;
                }
                group_num++;
            }
        };
        for (int i = 0; i < _n; i++) {
            if (ord[i] == -1) dfs(dfs, i);
        }
        for (auto& x : ids) {
            x = group_num - 1 - x;
        }
        return {group_num, ids};
    }

    std::vector<std::vector<int>> scc() {
        auto ids = scc_ids();
        int group_num = ids.first;
        std::vector<int> counts(group_num);
        for (auto x : ids.second) counts[x]++;
        std::vector<std::vector<int>> groups(ids.first);
        for (int i = 0; i < group_num; i++) {
            groups[i].reserve(counts[i]);
        }
        for (int i = 0; i < _n; i++) {
            groups[ids.second[i]].push_back(i);
        }
        return groups;
    }

  private:
    int _n;
    struct edge {
        int to;
    };
    std::vector<std::pair<int, edge>> edges;
};

}  // namespace internal

struct scc_graph {
  public:
    scc_graph() : internal(0) {}
    scc_graph(int n) : internal(n) {}

    void add_edge(int from, int to) {
        int n = internal.num_vertices();
        assert(0 <= from && from < n);
        assert(0 <= to && to < n);
        internal.add_edge(from, to);
    }

    std::vector<std::vector<int>> scc() { return internal.scc(); }

  private:
    internal::scc_graph internal;
};

vi group;
int first_group, last_group;

// bool dfs(int now, int target, vector<vector<pii>>& G, set<int>& used_edges, vector<bool> visited) {
//     if (now == target) return true;
//     visited[now] = true;
//     for (pii temp: G[now]) {
//         int v = temp.first;
//         if (visited[v]) continue;
//         int edge_idx = temp.second;
//         if (used_edges.count(edge_idx)) continue;
//         used_edges.insert(edge_idx);
//         if (dfs(v, target, G, used_edges, visited)) return true;
//         used_edges.erase(edge_idx);
//     }
//     return false;
// }



// �ӂ�\���\���� {�s��A�e�ʁA�t��}
struct edge { int to; ll cap; int rev; };
#define V 101000
int s, t; //s��start, t��goal
vector< vector<edge> > G(V, vector<edge>());; //�O���t�̗אڃ��X�g�\��
vector<bool> used(V); //DEF�Œ��ׂ����̃t���O

					  //from����to�֌������e��cap�̕ӂ��O���t�ɒǉ�����
void add_edge(int from, int to, ll cap) {
	edge a;
	a.to = to; a.cap = cap; a.rev = G[to].size();
	G[from].push_back(a);
	a.to = from; a.cap = 0; a.rev = G[from].size() - 1;
	G[to].push_back(a);
}

ll dfs(int v, int t, ll f) {
	if (v == t) {
		return f;
	}
	used[v] = true;
	for (int i = 0; i < G[v].size(); i++) {
		edge &e = G[v][i];
		if (!used[e.to] && e.cap > 0) {
			ll d = dfs(e.to, t, min(f, e.cap));
			if (d > 0) {
				e.cap -= d;
				G[e.to][e.rev].cap += d;
				return d;
			}
		}
	}
	return 0;
}

ll max_flow(int s, int t) {
	ll flow = 0;
	while (true) {
		fill(used.begin(), used.end(), false);
		ll f = dfs(s, t, INF);
		if (f == 0) return flow;
		flow += f;
        if (flow >= 2) return flow;
	}
}


signed main() {
    fio();
    int n, m;
    cin >> n >> m;
    scc_graph scc(n);

    vii G(n);
    rep (i, m) {
        int u, v;
        cin >> u >> v;
        u--; v--;
        G[u].push_back(v);
        scc.add_edge(u, v);
    }

    vii res = scc.scc();
    int k = res.size();
    if (k == 1) {
        cout << 0 << endl;
        return 0;
    }

    group.resize(n);
    rep (i, res.size()) {
        for (int u: res[i]) {
            group[u] = i;
        }
    }

    vii G2(k);
    vii rG2(k);
    rep (u, n) {
        for (int v: G[u]) {
            if (group[u] == group[v]) continue;
            G2[group[u]].push_back(group[v]);
            rG2[group[v]].push_back(group[u]);
            add_edge(group[u], group[v], 1);
        }
    }
    // vector<vector<pii>> G3(k);
    // int edge_num = 0;
    // rep (u, k) {
    //     for (int v: G2[u]) {
    //         G3[u].push_back(pii(v, edge_num++));
    //     }
    // }

    rep (u, k) {
        sort(all(G2[u]));
        UNIQUE(G2[u]);
        sort(all(rG2[u]));
        UNIQUE(rG2[u]);
    }

    vi in0, out0;
    rep (i, k) {
        if (G2[i].size() == 0) {
            out0.push_back(i);
        }
        if (rG2[i].size() == 0) {
            in0.push_back(i);
        }
    }

    if (in0.size() > 1 or out0.size() > 1) {
        cout << -1 << endl;
        return 0;
    }

    first_group = in0[0];
    last_group = out0[0];
    int F = max_flow(first_group, last_group);
    if (F < 2) {
        cout << -1 << endl;
        return 0;
    }

    // set<int> used_edges;
    // DEBUG_MAT(res);
    // DEBUG_MAT(G3);
    // vector<bool> visited(k);
    // if (not dfs(first_group, last_group, G3, used_edges, visited)) {
    //     cout << -1 << endl;
    //     return 0;
    // }
    // fill(all(visited), false);
    // if (not dfs(first_group, last_group, G3, used_edges, visited)) {
    //     cout << -1 << endl;
    //     return 0;
    // }

    vi dist(n, inf);
    queue<int> qu;
    for (int u: res[first_group]) {
        dist[u] = 0;
        qu.push(u);
    }
    // DEBUG_VEC(dist);
    // DEBUG_MAT(G);    

    int ans = inf;
    while (qu.size()) {
        int u = qu.front();
        qu.pop();
        if (group[u] == last_group) {
            chmin(ans, dist[u]);
        }

        for (int v: G[u]) {
            if (dist[v] > dist[u] + 1) {
                dist[v] = dist[u] + 1;
                qu.push(v);
            }
        }
    }
    cout << ans << endl;
}
accuracy: 0.35135135135135137
time_ms: 30
memory_kb: 26632
final_rank: 17

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;
// const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

template< typename T = int >
struct Edge {
  int from, to;
  T cost;
  int idx;

  Edge() = default;

  Edge(int from, int to, T cost = 1, int idx = -1) : from(from), to(to), cost(cost), idx(idx) {}

  operator int() const { return to; }
};

template< typename T = int >
struct Graph {
  vector< vector< Edge< T > > > g;
  int es;

  Graph() = default;

  explicit Graph(int n) : g(n), es(0) {}

  size_t size() const {
    return g.size();
  }

  void add_directed_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es++);
  }

  void add_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es);
    g[to].emplace_back(to, from, cost, es++);
  }

  void read(int M, int padding = -1, bool weighted = false, bool directed = false) {
    for(int i = 0; i < M; i++) {
      int a, b;
      cin >> a >> b;
      a += padding;
      b += padding;
      T c = T(1);
      if(weighted) cin >> c;
      if(directed) add_directed_edge(a, b, c);
      else add_edge(a, b, c);
    }
  }
};

template< typename T = int >
using Edges = vector< Edge< T > >;

/**
 * @brief Strongly-Connected-Components(強連結成分分解)
 */
template< typename T = int >
struct StronglyConnectedComponents : Graph< T > {
public:
  using Graph< T >::Graph;
  using Graph< T >::g;
  vector< int > comp;
  Graph< T > dag;
  vector< vector< int > > group;

  void build() {
    rg = Graph< T >(g.size());
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        rg.add_directed_edge(e.to, e.from, e.cost);
      }
    }
    comp.assign(g.size(), -1);
    used.assign(g.size(), 0);
    for(int i = 0; i < g.size(); i++) dfs(i);
    reverse(begin(order), end(order));
    int ptr = 0;
    for(int i : order) if(comp[i] == -1) rdfs(i, ptr), ptr++;
    dag = Graph< T >(ptr);
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        int x = comp[e.from], y = comp[e.to];
        if(x == y) continue;
        dag.add_directed_edge(x, y, e.cost);
      }
    }
    group.resize(ptr);
    for(int i = 0; i < g.size(); i++) {
      group[comp[i]].emplace_back(i);
    }
  }

  int operator[](int k) const {
    return comp[k];
  }

private:
  vector< int > order, used;
  Graph< T > rg;

  void dfs(int idx) {
    if(exchange(used[idx], true)) return;
    for(auto &to : g[idx]) dfs(to);
    order.push_back(idx);
  }

  void rdfs(int idx, int cnt) {
    if(comp[idx] != -1) return;
    comp[idx] = cnt;
    for(auto &to : rg.g[idx]) rdfs(to, cnt);
  }
};


/**
 * @brief Ford-Fulkerson(最大流)
 * @docs docs/ford-fulkerson.md
 */
template< typename flow_t >
struct FordFulkerson {
  struct edge {
    int to;
    flow_t cap;
    int rev;
    bool isrev;
    int idx;
  };

  vector< vector< edge > > graph;
  vector< int > used;
  const flow_t INF;
  int timestamp;

  explicit FordFulkerson(int V) : INF(numeric_limits< flow_t >::max()), graph(V), used(V, -1), timestamp(0) {}

  void add_edge(int from, int to, flow_t cap, int idx = -1) {
    graph[from].emplace_back((edge) {to, cap, (int) graph[to].size(), false, idx});
    graph[to].emplace_back((edge) {from, 0, (int) graph[from].size() - 1, true, idx});
  }

  flow_t find_augment_path(int idx, const int t, flow_t flow) {
    if(idx == t) return flow;
    used[idx] = timestamp;
    for(auto &e : graph[idx]) {
      if(e.cap > 0 && used[e.to] != timestamp) {
        flow_t d = find_augment_path(e.to, t, min(flow, e.cap));
        if(d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  flow_t max_flow(int s, int t) {
    flow_t flow = 0;
    for(flow_t f; (f = find_augment_path(s, t, INF)) > 0; timestamp++) {
      flow += f;
      if(flow >= 2) break;
    }
    return flow;
  }

  void output() {
    for(int i = 0; i < graph.size(); i++) {
      for(auto &e : graph[i]) {
        if(e.isrev) continue;
        auto &rev_e = graph[e.to][e.rev];
        cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
      }
    }
  }
};

/**
 * @brief Dijkstra(単一始点最短路)
 * @docs docs/dijkstra.md
 */
template< typename T >
struct ShortestPath {
  vector< T > dist;
  vector< int > from, id;
};

int main() {
  int N, M;
  cin >> N >> M;
  vector< int > A(M), B(M);
  Graph<> rg(N);
  StronglyConnectedComponents<> scc(N);
  for(int i = 0; i < M; i++) {
    cin >> A[i] >> B[i];
    --A[i], --B[i];
    scc.add_directed_edge(A[i], B[i]);
    rg.add_directed_edge(B[i], A[i]);
  }
  scc.build();
  if(scc.dag.size() == 1) {
    cout << 0 << "\n";
    exit(0);
  }
  vector< int > in(N), out(N);
  for(int i = 0; i < scc.dag.size(); i++) {
    if(scc.dag.g[i].size()) {
      in[i] = true;
    }
    for(auto &t : scc.dag.g[i]) {
      out[t] = true;
    }
  }

  vector< int > latte, malta;
  for(int i = 0; i < N; i++) {
    if(!in[i]) {
      latte.emplace_back(i);
    }
    if(!out[i]) {
      malta.emplace_back(i);
    }
  }
  if(latte.size() != 1 && malta.size() != 1) {
    cout << -1 << "\n";
    exit(0);
  }


  FordFulkerson< int > flow(scc.size() + 2);
  for(int i = 0; i < M; i++) {
    flow.add_edge(A[i], B[i], 1);
  }
  for(auto &p : scc.group[malta[0]]) {
    flow.add_edge(scc.size(), p, inf);
  }
  for(auto &p : scc.group[latte[0]]) {
    flow.add_edge(p, scc.size() + 1, inf);
  }
  if(flow.max_flow(scc.size(), scc.size() + 1) <= 1) {
    cout << "-1\n";
    exit(0);
  }


  using T = int;
  const auto INF = numeric_limits< T >::max();
  vector< T > dist(scc.size(), INF);
  vector< int > from(scc.size(), -1), id(scc.size(), -1);
  using Pi = pair< T, int >;
  priority_queue< Pi, vector< Pi >, greater<> > que;
  for(auto &p : scc.group[latte[0]]) {
    dist[p] = 0;
    que.emplace(0, p);
  }
  while(!que.empty()) {
    T cost;
    int idx;
    tie(cost, idx) = que.top();
    que.pop();
    if(dist[idx] < cost) continue;
    for(auto &e : rg.g[idx]) {
      auto next_cost = cost + e.cost;
      if(dist[e.to] <= next_cost) continue;
      dist[e.to] = next_cost;
      from[e.to] = idx;
      id[e.to] = e.idx;
      que.emplace(dist[e.to], e.to);
    }
  }
  int ans = inf;
  for(auto &p : scc.group[malta[0]]) {
    chmin(ans, dist[p]);
  }
  if(ans >= inf) ans = -1;
  cout << ans << "\n";
}
accuracy: 0.5
time_ms: 40
memory_kb: 30508
final_rank: 13

code_snippet: #include <bits/stdc++.h>

using namespace std;

using int64 = long long;
const int mod = 1e9 + 7;
// const int mod = 998244353;

const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;

struct IoSetup {
  IoSetup() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    cout << fixed << setprecision(10);
    cerr << fixed << setprecision(10);
  }
} iosetup;


template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 > &p) {
  os << p.first << " " << p.second;
  return os;
}

template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
  is >> p.first >> p.second;
  return is;
}

template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
  for(int i = 0; i < (int) v.size(); i++) {
    os << v[i] << (i + 1 != v.size() ? " " : "");
  }
  return os;
}

template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
  for(T &in : v) is >> in;
  return is;
}

template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }

template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }

template< typename T = int64 >
vector< T > make_v(size_t a) {
  return vector< T >(a);
}

template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
  return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}

template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
  t = v;
}

template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
  for(auto &e : t) fill_v(e, v);
}

template< typename F >
struct FixPoint : F {
  FixPoint(F &&f) : F(forward< F >(f)) {}

  template< typename... Args >
  decltype(auto) operator()(Args &&... args) const {
    return F::operator()(*this, forward< Args >(args)...);
  }
};

template< typename F >
inline decltype(auto) MFP(F &&f) {
  return FixPoint< F >{forward< F >(f)};
}

template< typename T = int >
struct Edge {
  int from, to;
  T cost;
  int idx;

  Edge() = default;

  Edge(int from, int to, T cost = 1, int idx = -1) : from(from), to(to), cost(cost), idx(idx) {}

  operator int() const { return to; }
};

template< typename T = int >
struct Graph {
  vector< vector< Edge< T > > > g;
  int es;

  Graph() = default;

  explicit Graph(int n) : g(n), es(0) {}

  size_t size() const {
    return g.size();
  }

  void add_directed_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es++);
  }

  void add_edge(int from, int to, T cost = 1) {
    g[from].emplace_back(from, to, cost, es);
    g[to].emplace_back(to, from, cost, es++);
  }

  void read(int M, int padding = -1, bool weighted = false, bool directed = false) {
    for(int i = 0; i < M; i++) {
      int a, b;
      cin >> a >> b;
      a += padding;
      b += padding;
      T c = T(1);
      if(weighted) cin >> c;
      if(directed) add_directed_edge(a, b, c);
      else add_edge(a, b, c);
    }
  }
};

template< typename T = int >
using Edges = vector< Edge< T > >;

/**
 * @brief Strongly-Connected-Components(強連結成分分解)
 */
template< typename T = int >
struct StronglyConnectedComponents : Graph< T > {
public:
  using Graph< T >::Graph;
  using Graph< T >::g;
  vector< int > comp;
  Graph< T > dag;
  vector< vector< int > > group;

  void build() {
    rg = Graph< T >(g.size());
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        rg.add_directed_edge(e.to, e.from, e.cost);
      }
    }
    comp.assign(g.size(), -1);
    used.assign(g.size(), 0);
    for(int i = 0; i < g.size(); i++) dfs(i);
    reverse(begin(order), end(order));
    int ptr = 0;
    for(int i : order) if(comp[i] == -1) rdfs(i, ptr), ptr++;
    dag = Graph< T >(ptr);
    for(int i = 0; i < g.size(); i++) {
      for(auto &e : g[i]) {
        int x = comp[e.from], y = comp[e.to];
        if(x == y) continue;
        dag.add_directed_edge(x, y, e.cost);
      }
    }
    group.resize(ptr);
    for(int i = 0; i < g.size(); i++) {
      group[comp[i]].emplace_back(i);
    }
  }

  int operator[](int k) const {
    return comp[k];
  }

private:
  vector< int > order, used;
  Graph< T > rg;

  void dfs(int idx) {
    if(exchange(used[idx], true)) return;
    for(auto &to : g[idx]) dfs(to);
    order.push_back(idx);
  }

  void rdfs(int idx, int cnt) {
    if(comp[idx] != -1) return;
    comp[idx] = cnt;
    for(auto &to : rg.g[idx]) rdfs(to, cnt);
  }
};


/**
 * @brief Ford-Fulkerson(最大流)
 * @docs docs/ford-fulkerson.md
 */
template< typename flow_t >
struct FordFulkerson {
  struct edge {
    int to;
    flow_t cap;
    int rev;
    bool isrev;
    int idx;
  };

  vector< vector< edge > > graph;
  vector< int > used;
  const flow_t INF;
  int timestamp;

  explicit FordFulkerson(int V) : INF(numeric_limits< flow_t >::max()), graph(V), used(V, -1), timestamp(0) {}

  void add_edge(int from, int to, flow_t cap, int idx = -1) {
    graph[from].emplace_back((edge) {to, cap, (int) graph[to].size(), false, idx});
    graph[to].emplace_back((edge) {from, 0, (int) graph[from].size() - 1, true, idx});
  }

  flow_t find_augment_path(int idx, const int t, flow_t flow) {
    if(idx == t) return flow;
    used[idx] = timestamp;
    for(auto &e : graph[idx]) {
      if(e.cap > 0 && used[e.to] != timestamp) {
        flow_t d = find_augment_path(e.to, t, min(flow, e.cap));
        if(d > 0) {
          e.cap -= d;
          graph[e.to][e.rev].cap += d;
          return d;
        }
      }
    }
    return 0;
  }

  flow_t max_flow(int s, int t) {
    flow_t flow = 0;
    for(flow_t f; (f = find_augment_path(s, t, INF)) > 0; timestamp++) {
      flow += f;
    }
    return flow;
  }

  void output() {
    for(int i = 0; i < graph.size(); i++) {
      for(auto &e : graph[i]) {
        if(e.isrev) continue;
        auto &rev_e = graph[e.to][e.rev];
        cout << i << "->" << e.to << " (flow: " << rev_e.cap << "/" << e.cap + rev_e.cap << ")" << endl;
      }
    }
  }
};

/**
 * @brief Dijkstra(単一始点最短路)
 * @docs docs/dijkstra.md
 */
template< typename T >
struct ShortestPath {
  vector< T > dist;
  vector< int > from, id;
};

int main() {
  int N, M;
  cin >> N >> M;
  vector< int > A(M), B(M);
  Graph<> rg(N);
  StronglyConnectedComponents<> scc(N);
  for(int i = 0; i < M; i++) {
    cin >> A[i] >> B[i];
    --A[i], --B[i];
    scc.add_directed_edge(A[i], B[i]);
    rg.add_directed_edge(B[i], A[i]);
  }
  scc.build();
  if(scc.dag.size() == 1) {
    cout << 0 << "\n";
    exit(0);
  }
  vector< int > in(N), out(N);
  for(int i = 0; i < scc.dag.size(); i++) {
    if(scc.dag.g[i].size()) {
      in[i] = true;
    }
    for(auto &t : scc.dag.g[i]) {
      out[t] = true;
    }
  }

  vector< int > latte, malta;
  for(int i = 0; i < N; i++) {
    if(!in[i]) {
      latte.emplace_back(i);
    }
    if(!out[i]) {
      malta.emplace_back(i);
    }
  }
  if(latte.size() != 1 && malta.size() != 1) {
    cout << -1 << "\n";
    exit(0);
  }


  FordFulkerson< int > flow(scc.size());
  for(int i = 0; i < scc.size(); i++) {
    for(auto &p : scc.dag.g[i]) {
      flow.add_edge(i, p, 1);
    }
  }
  if(flow.max_flow(malta[0], latte[0]) <= 1) {
    cout << "-1\n";
    exit(0);
  }


  using T = int;
  const auto INF = numeric_limits< T >::max();
  vector< T > dist(scc.size(), INF);
  vector< int > from(scc.size(), -1), id(scc.size(), -1);
  using Pi = pair< T, int >;
  priority_queue< Pi, vector< Pi >, greater<> > que;
  for(auto &p : scc.group[latte[0]]) {
    dist[p] = 0;
    que.emplace(0, p);
  }
  while(!que.empty()) {
    T cost;
    int idx;
    tie(cost, idx) = que.top();
    que.pop();
    if(dist[idx] < cost) continue;
    for(auto &e : rg.g[idx]) {
      auto next_cost = cost + e.cost;
      if(dist[e.to] <= next_cost) continue;
      dist[e.to] = next_cost;
      from[e.to] = idx;
      id[e.to] = e.idx;
      que.emplace(dist[e.to], e.to);
    }
  }
  int ans = inf;
  for(auto &p : scc.group[malta[0]]) {
    chmin(ans, dist[p]);
  }
  if(ans >= inf) ans = -1;
  cout << ans << "\n";
}
accuracy: 0.5
time_ms: 50
memory_kb: 29876
final_rank: 14