#ifndef ENV_AC
    #define ENV_AC
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <fstream>
    #include <iostream>
    #include <sstream>
    #include <iomanip>
    #include <algorithm>
    #include <bitset>
    #include <array>
    #include <vector>
    #include <queue>
    #include <set>
    #include <cmath> // 変数名にy1が使えなくなるかも…。
    #include <map>
    #include <unordered_map>
    #include <unordered_set>
    #include <limits>
    #include <functional>
    #include <string>
    #include <ext/rope>

    using int128_t = __int128_t;
    std::istream &operator>>(std::istream& input, int128_t& value) { // int128_tの入力。入力が64bitに収まる前提。
        int64_t tmp; input >> tmp; value = tmp;
        return input;
    }
    std::ostream &operator<<(std::ostream& output, const int128_t value) { // int128_tの出力。出力が64bitに収まる前提。
        output << (int64_t)value;
        return output;
    }

    namespace std {
        template<> class hash<int128_t>{
            public:
            size_t operator () ( const int128_t &x ) const {
                int64_t INF64 = std::numeric_limits<int64_t>::max();
                int64_t y1 = x / INF64;
                int64_t y2 = x % INF64;
                return hash<int64_t>()(y1) ^ hash<int64_t>()(y2);
            }
        };
    }

    int128_t imax(const int128_t a, const int128_t b) { return std::max(a, b); } // std::max, std::min は型が違うとエラーになるため、ラッパーを作る。
    int128_t imin(const int128_t a, const int128_t b) { return std::min(a, b); }
    int128_t iabs(const int128_t x) { return 0 <= x ? x : -x; }
    int128_t ipow(const int128_t x, const int128_t n) { int128_t ret = 1; for (int i = 0; i < n; i++) { ret *= x; } return ret; }

    template <int128_t mod> class Mod_Int {
        public:
        int128_t val;

        void calc() {
            if (val < 0) { val += ((iabs(val) + mod) / mod) * mod; }
            val %= mod;
        }
        Mod_Int(const int128_t _val = 0) { val = _val; calc(); }
        int128_t INT() { return val; } // 使用は非想定
        int128_t MOD() { return mod; } // 使用は非想定
        Mod_Int operator-() const { return Mod_Int(-val); }
        Mod_Int operator+(const Mod_Int &r) const { return Mod_Int(val + r.val); }
        Mod_Int operator-(const Mod_Int &r) const { return Mod_Int(val - r.val); }
        Mod_Int operator*(const Mod_Int &r) const { return Mod_Int(val * r.val); }
        //Mod_Int operator/(const Mod_Int &r) const { return ; } // ユークリッド互除法を使うべきだが保留。
        Mod_Int& operator+=(const Mod_Int &r) { val += r.val; calc(); return *this; }
        Mod_Int& operator-=(const Mod_Int &r) { val -= r.val; calc(); return *this; }
        Mod_Int& operator*=(const Mod_Int &r) { val *= r.val; calc(); return *this; }
        Mod_Int& operator++() { return (*this) += 1; }
        Mod_Int& operator--() { return (*this) -= 1; }
        Mod_Int operator++(int) { Mod_Int tmp = *this; ++*this; return tmp; }
        Mod_Int operator--(int) { Mod_Int tmp = *this; --*this; return tmp; }
        bool operator==(const Mod_Int &r) const { return val == r.val; }
        bool operator!=(const Mod_Int &r) const { return val != r.val; }

        friend std::istream &operator>>(std::istream& input, Mod_Int& r) { 
            int128_t tmp; input >> tmp;
            r = Mod_Int(tmp);
            return input;
        }
        friend std::ostream &operator<<(std::ostream& output, const Mod_Int& r) { 
            output << r.val;
            return output;
        }
    };

    // binary search result
    struct BSR {
        bool found; // 条件を満たす範囲が見つかったか。falseの場合、begin,endは意味を持たない。
        int128_t begin; // [begin, end]で条件が成り立つ。
        int128_t end;
        BSR(bool found_in, int128_t begin_in, int128_t end_in) { found = found_in; begin = begin_in; end = end_in; }
    };

    //template<class Fn> BSR binary_search(int128_t L, int128_t R, Fn func) {
    BSR binary_search(int128_t L, int128_t R, std::function<bool(int128_t)> func) {
        const bool res_L = func(L);
        const bool res_R = func(R);
        if (res_L && res_R) {
            return BSR(true, L, R);
        } else if (!res_L && !res_R) {
            return BSR(false, 0, 0);
        } else {
            int128_t lb = L;
            int128_t ub = R;
            while (lb + 1 < ub) {
                int128_t mid = (lb + ub) / 2;
                if (res_L == func(mid)) {
                    lb = mid;
                } else {
                    ub = mid;
                }
            }
            return res_L ? BSR(true, L, lb) : BSR(true, ub, R);
        }
    }

    #define rep(i, begin, end) for(int64_t i = ((int64_t)begin); i <= ((int64_t)end); i++) // (int64_t)end としておくと、end = v.size() - 2 みたいな入力で、v.size()が1でも正常(end = -1になる）に挙動する。
    #define rev(i, begin, end) for(int64_t i = ((int64_t)begin); ((int64_t)end) <= i; i--) // int128_tにすると、3重ループでコンパイルエラーになったのでint64_tにしておく。

    #define input1(begin, end, v1) v1.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i]; }
    #define input2(begin, end, v1, v2) v1.resize((end)+1); v2.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i]; } 
    #define input3(begin, end, v1, v2, v3) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i] >> v3[i]; }
    #define input4(begin, end, v1, v2, v3, v4) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); v4.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i] >> v3[i] >> v4[i]; } 
    #define input5(begin, end, v1, v2, v3, v4, v5) v1.resize((end)+1); v2.resize((end)+1); v3.resize((end)+1); v4.resize((end)+1); v5.resize((end)+1); for (int i = (begin); i <= (end); i++) { std::cin >> v1[i] >> v2[i] >> v3[i] >> v4[i] >> v5[i]; }  
    // input_arrayはbegin = 0のときのみ動作確認。Aの要素の型をテンプレートにして関数にしたほうが丁寧かもしれない。
    #define input_array(begin, N, M, A) A.resize((begin)+(N)); for (int i = 0; i < (begin)+(N); i++) { A[i].resize((begin)+(M)); } for (int i = begin; i < (begin)+(N); i++) { for (int j = begin; j < (begin)+(M); j++) { std::cin >> A[i][j]; }}

    std::vector<int128_t> irange(const int128_t begin, const int128_t end) {
        std::vector<int128_t> ret; for (int128_t i = begin; i <= end; i++) { ret.push_back(i); }
        return ret;
    }

    template <typename T>
    std::vector<T> accumulate_vec(const std::vector<T>& vec, const bool reverse = false) {
        std::vector<T> ret; ret.resize(vec.size());
        if (0 < vec.size()) {
            if (reverse == false) {
                ret[0] = vec[0];
                for (int i = 1; i < ret.size(); i++) {
                    ret[i] = ret[i-1] + vec[i];
                }
            } else {
                ret[ret.size()-1] = vec[ret.size()-1];
                for (int i = ret.size() - 2; 0 <= i; i--) {
                    ret[i] = ret[i+1] + vec[i];
                }
            }
        }
        return ret;
    }

    template <typename T>
    T cal_pow(T x, int128_t n, T tmp = T(1)) {
        // 累乗の計算。
        while (n > 0) {
            if (n & 1) { tmp = tmp * x; }
            x = x * x;
            n = (n >> 1);
        }
        return tmp;
    }

    std::vector<int128_t> digit(int128_t n, const int128_t b) {
        // 基数bでの表示。0は0桁。非常に大きい数を入れても問題ないようにint128_tとする。
        // size()をとれば桁数になる。
        assert(1 < b);
        std::vector<int128_t> ret;
        while (0 < n) {
            ret.push_back(n % b);
            n /= b;
        }
        return ret;
    }

    template <typename T>
    void printvec(const std::vector<T>& vec) {
        for (int i = 0; i < vec.size(); i++) { std::cout << vec[i] << " "; } std::cout << std::endl;
    }
#endif

// 有向グラフのクラス。
// ダイクストラ、ベルマン・フォード、ワーシャルフロイド、最大フローに対応。
// 最大フローを求める問題で、costをint128_tにしたらMLEしたことがあるので、costはint64_tにしておく。
class Directed_Graph {
    public:
    struct Edge { 
        int to; int64_t cost;
    };
    typedef std::vector<std::vector<Edge>> adj_list;
    adj_list G;
    Directed_Graph() {}
    Directed_Graph(const int greatest_node_id) {
        G.resize(greatest_node_id + 1);
    }
    void add_directed_edge(const int from, const int to, const int64_t cost) {
        Edge edge; edge.to = to; edge.cost = cost;
        G[from].push_back(edge);
    }
    void add_undirected_edge(const int node1, const int node2, const int64_t cost) {
        add_directed_edge(node1, node2, cost);
        add_directed_edge(node2, node1, cost);
    }

    // 点sからの最短距離の配列を返す。
    // 戻りの値としてint128_tを用い、初期値としてint64_tの最大値を用いるのは、dist[v] + edge.costの計算でのオーバーフローを防ぐため。
    // 正しい最短距離がint64_tの最大値を超えるような事態は想定していないので、最終的にdist[v] == std::numeric_limits<int64_t>::max()だった場合、vには到達できないことを意味する。
    std::vector<int128_t> Dijkstra(int s) const {
        std::vector<int128_t> dist;
        dist.resize(G.size(), std::numeric_limits<int64_t>::max());

        typedef std::pair<int128_t, int> Pair;
        std::priority_queue <Pair, std::vector<Pair>, std::greater<Pair>> que;
        dist[s] = 0;
        que.push(Pair(0, s));

        while (!que.empty()) {
            Pair pair = que.top(); que.pop();
            int v = pair.second;
            if (dist[v] < pair.first) { continue; }
            for (Edge edge : G[v]) {
                if (dist[v] + edge.cost < dist[edge.to]) {
                    dist[edge.to] = dist[v] + edge.cost;
                    que.push(Pair(dist[edge.to], edge.to));
                }
            }
        }
        return dist;
    }

    // Dijkstra法を行った後に、各点に関する最短経路の1つ前の点を計算する。
    // Dijkstra法の中に組み込む方が自然だが、Dijkstra()を複雑にしないように分離する。
    std::vector<int> Dijkstra_prev(const int s, const std::vector<int128_t>& dist) const {
        const int node_num = G.size();
        std::vector<int> prev; prev.resize(node_num, -1);
        for (int i = 0; i < node_num; i++) {
            for (Edge edge : G[i]) {
                if (dist[i] + edge.cost == dist[edge.to]) { prev[edge.to] = i; }
            }
        }
        return prev;
    }

    // Dijkstra法で、s->t 最短路を求める。{s,...,t}の形式で出力。
    // 到達できない場合は空ベクタ、t==sの場合{s}を返す。
    std::vector<int> Dijkstra_path(const int s, const int t) const {
        std::vector<int128_t> dist = Dijkstra(s);
        std::vector<int> prev = Dijkstra_prev(s, dist);
        std::vector<int> path;
        int tmp = t;
        while (tmp != s && prev[tmp] != -1) {
            path.push_back(tmp);
            tmp = prev[tmp];
        }
        if (tmp == s) { path.push_back(tmp); }
        std::reverse(path.begin(), path.end());
        return path;
    }

    // Bellman_Ford法により、sからの距離を返す。
    // パスの長さがnode_num以上になった場合、負の閉路が存在するため距離をNEG_INFにする。（負の閉路が無ければ最短パスの辺数は必ずnode_num-1以下のため）
    // *std::min_element(dist.begin(), dist.end()) == NEG_INF ならば負の閉路が存在し、dist[i] == NEG_INFならばiへのパスを負の無限にできる。
    // 計算量は、O(node_num * edge_num)
    std::vector<int128_t> Bellman_Ford(const int s) {
        std::vector<int128_t> dist;
        const int128_t INF = std::numeric_limits<int64_t>::max();
        const int128_t NEG_INF = std::numeric_limits<int64_t>::min();
        const int node_num = G.size();
        dist.resize(node_num, INF);
        dist[s] = 0;
        for (int n = 1; n <= node_num * 2; n++) {
            for (int i = 0; i < node_num; i++) {
                if (dist[i] != INF) {
                    for (auto e : G[i]) {
                        if (dist[i] + e.cost < dist[e.to]) {
                            if (n < node_num) {
                                dist[e.to] = dist[i] + e.cost;
                            } else {
                                dist[e.to] = NEG_INF;
                            }
                        }
                    }
                }
            }
        }
        return dist;
    }

    std::vector<std::vector<int128_t>> Warshall_Floyd() {
        const int128_t INF = std::numeric_limits<int64_t>::max();
        const int node_num = G.size();
        std::vector<std::vector<int128_t>> dist; dist.resize(node_num);
        for (int i = 0; i < dist.size(); i++) {
            dist[i].resize(node_num, INF);
            dist[i][i] = 0;
            for (auto e : G[i]) {
                dist[i][e.to] = std::min(dist[i][e.to], (int128_t)e.cost);
            }
        }
        for (int k = 0; k < node_num; k++) {
            for (int i = 0; i < node_num; i++) {
                for (int j = 0; j < node_num; j++) {
                    dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
                }
            }
        }
        return dist;
    }

    // 連結でない無向グラフが与えられた時に、各頂点に連結成分のインデックスを割り当てる。インデックスはbeginから。
    std::vector<int> connected_index(const int begin, const int end) {
        std::vector<int> ret; ret.resize(end+1, -1);
        std::function<void(int, int)> dfs = [&] (int n, int i) {
            ret[n] = i;
            for (Edge e : G[n]) {
                if (ret[e.to] == -1) { dfs(e.to, i); }
            }
        };
        int tmp = begin;
        for (int n = begin; n <= end; n++) {
            if (ret[n] == -1) { 
                dfs(n, tmp);
                tmp++;
            }
        }
        assert(tmp <= end + 1);
        return ret;
    }

    // 無向グラフが与えられた時に、bipartiteかどうか判定。bipartiteの場合、第二引数に各頂点に関する±1が入る。
    std::pair<bool, std::vector<int>> is_bipartite(const int begin, const int end) {
        std::vector<int> ret; ret.resize(end+1, 0);
        std::function<bool(int, int)> dfs = [&] (int n, int c) {
            if (ret[n] == -c) { return false; }
            if (ret[n] == c) { return true; }
            ret[n] = c;
            for (Edge e : G[n]) {
                if (!dfs(e.to, -c)) { return false; }
            }
            return true;
        };
        for (int i = begin; i <= end; i++) {
            if (ret[i] == 0 && !dfs(i, 1)) {
                return std::pair<bool, std::vector<int>>({false, ret});
            }
        }
        return std::pair<bool, std::vector<int>>({true, ret});
    }

    // beginからendまで、dfsでの帰りがけ順に並べる。
    // 帰りがけ順でuがvの後に出てきた場合、以下のいずれかが成り立つ。
    // 1. uからvに到達可能
    // 2. uからvに到達不可能かつvからuに到達不可能
    // すなわち、vからuに到達可能だが、uからvに到達不可能という事象が否定される。
    std::vector<int> dfs_postorder(const int begin, const int end) const {
        std::vector<int> ret;
        std::vector<bool> used; used.resize(end+1, false);
        std::function<void(int)> dfs = [&] (int n) {
            used[n] = true;
            for (Edge e : G[n]) {
                if (!used[e.to]) { dfs(e.to); }
            }
            ret.push_back(n);
        };
        for (int i = begin; i <= end; i++) {
            if (!used[i]) { dfs(i); }
        }
        assert(ret.size() == end - begin + 1);
        return ret;
    }

    // 元のグラフの逆辺集合を返す。
    adj_list reverse_graph() const {
        const int node_num = G.size();
        adj_list rG; rG.resize(node_num);
        for (int i = 0; i < node_num; i++) {
            for (Edge e : G[i]) {
                Edge re; re.to = i; re.cost = e.cost;
                rG[e.to].push_back(re);
            }
        }
        return rG;
    }

    // 強結合の要素をまとめたDAGにおいてトポロジカルソートされるように、強結合関係の要素に同じindexを与える。
    // 逆辺でdfsを行うため、元のグラフでは到達点から始点に到達可能である。
    // 帰りがけ順の後ろからdfsを行っているので、始点から到達点へは、元のグラフでも到達可能である。よって同じ番号が与えられるなら強結合である。
    // また強結合なら、逆辺dfsで到達可能なため、このアルゴリズムで同じ番号になることが強結合の必要十分条件である。
    // 帰りがけ順のうしろから見ているため、番号が大きい成分に関しては、到達可能 or どちらの方向にも到達不可能　のいずれかが成り立つのでトポロジカルソートできている。
    std::vector<int> scc_topological(const int begin, const int end) const {
        std::vector<int> post = dfs_postorder(begin, end);
        adj_list rG = reverse_graph();
        std::vector<int> ret; ret.resize(end+1, -1);
        int cnt = begin;
        std::function<void(int)> dfs = [&] (int n) {
            ret[n] = cnt;
            for (Edge e : rG[n]) {
                if (ret[e.to] == -1) { dfs(e.to); }
            }
        };
        for (int i = post.size()-1; 0 <= i; i--) {
            if (ret[post[i]] == -1) {
                dfs(post[i]);
                cnt++;
            }
        }
        assert(cnt <= end + 1);
        return ret;
    }

    // 閉路が存在するかどうか。閉路が存在することと、強結合要素で2つ以上の頂点を持つものは同値。
    bool has_cycle(const int begin, const int end) const {
        std::vector<int> scc = scc_topological(begin, end);
        std::unordered_set<int> st;
        for (int i = begin; i <= end; i++) {
            st.insert(scc[i]);
        }
        return st.size() < end - begin + 1;
    }
};

std::vector<int> cand;

//--code begin--

int128_t N, M;
std::vector<int128_t> A, B;
//std::string S, T;
//std::vector<std::string> ;
//double A, B, H, W;
//std::vector<double> ;

const int128_t MAX_N = 1e3 + 10;
//const int128_t MOD = ;
const int128_t INF = std::numeric_limits<int64_t>::max(); const int128_t NEG_INF = std::numeric_limits<int64_t>::min();
//using pair = std::pair<int128_t, int128_t>;
//using mnt = Mod_Int<MOD>;

//std::priority_queue<pair> pq;

Directed_Graph dg(MAX_N);
std::vector<int128_t> ret[MAX_N];
std::set<int128_t> st[MAX_N];
std::vector<int128_t> dist[MAX_N];

int main(int argc, char **argv) {
    std::cin.tie(0);
   	std::ios::sync_with_stdio(false);
    std::cout << std::fixed << std::setprecision(15);

    std::cin >> N >> M;
    input2(1, M, A, B);

    rep (i, 1, M) {
        dg.add_directed_edge(A[i], B[i], 1);
    }

    auto scc = dg.scc_topological(1, N);
    for (int128_t i = 1; i <= N; i++) {
        ret[scc[i]].push_back(i);
        st[scc[i]].insert(i);
    }

    

    rep (i, 0, N) {
        if (1 < ret[i].size()) {
            int128_t best1 = 0;
            int128_t best2 = 0;
            int128_t best_cur = INF;
            rep (j, 0, ret[i].size() - 1) {
                for (auto e : dg.G[ret[i][j]]) {
                    if (st[i].count(e.to)) {
                        if (dist[e.to].size() == 0) {
                            dist[e.to] = dg.Dijkstra(e.to);
                        }
                        if (dist[e.to][ret[i][j]] < best_cur) {
                            best_cur = dist[e.to][ret[i][j]];
                            best1 = ret[i][j];
                            best2 = e.to;
                        }
                    }
                }
            }
            auto path = dg.Dijkstra_path(best2, best1);
            std::cout << path.size() << std::endl;
            for (int128_t node : path) {
                std::cout << node << std::endl;
            }
            return 0;

            /*
            int128_t begin = *ret[i].begin();
            for (int128_t next : ret[i]) {
                if (next != begin && ret[i].count(next) == 1) {
                    auto path = dg.Dijkstra_path(next, begin);
                    if (cand.size() == 0 || path.size() < cand.size()) {
                        cand = path;
                    }
                }
            }
            */
        }
    }
    
    std::cout << -1 << std::endl;
    return 0;

}


Measured memory_bytes: 16384