using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
 
using P = pair<int, int>;
 
class Program
{
    static StreamWriter sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
    static Scan sc = new Scan();
    const int M = 1000000007;
    // const int M = 998244353;
    static void Main()
    {
        int n, m;
        sc.Multi(out n, out m);
        var edges = new List<pair<long, int>>[n];
        var ng = new bool[n];
        for (int i = 0; i < n; i++)
        {
            edges[i] = new List<pair<long, int>>();
        }
        for (int i = 0; i < m; i++)
        {
            int a, b;
            sc.Multi(out a, out b);
            edges[a].Add(util.make_pair((long)0, b));
            edges[b].Add(util.make_pair((long)1, a));
            ng[b] = true;
        }
        var lis = new List<int>();
        for (int i = 0; i < n; i++)
            if (!ng[i]) lis.Add(i);
        
        var nedges = new List<pair<long, int>>[lis.Count];
        for (int i = 0; i < lis.Count; i++)
        {
            var dist = new long[n];
            for (int j = 0; j < n; j++)
                dist[j] = M;
            
            dist[lis[i]] = 0;
            var q = new Queue<int>();
            q.Enqueue(lis[i]);
            while (q.Any())
            {
                var qq = new Queue<int>();
                qq.Enqueue(q.Dequeue());
                while (qq.Any())
                {
                    int p = qq.Dequeue();
                    foreach (var item in edges[p])
                    {
                        if (dist[item.v2] > dist[p] + item.v1) {
                            dist[item.v2] = dist[p] + item.v1;
                            if (item.v1 == 0)
                                qq.Enqueue(item.v2);
                            else
                                q.Enqueue(item.v2);
                        }
                    }
                }
            }
            nedges[i] = new List<pair<long, int>>();

            for (int j = 0; j < lis.Count; j++)
                if (i != j && dist[lis[j]] < M)
                    nedges[i].Add(util.make_pair(dist[lis[j]], j));
        }
        var ans = new List<int>();
        long min = M;
        for (int i = 0; i < lis.Count; i++)
        {
            var c = MSA.getmincost(nedges, i);
            if (c < min) {
                min = c;
                ans.Clear();
                ans.Add(lis[i]);
            }
            else if (c == min) {
                ans.Add(lis[i]);
            }
        }
        sw.WriteLine(ans.Count + " " + min);
        bool fir = true;
        foreach (var item in ans)
        {
            if (fir) sw.Write(item);
            else sw.Write(" " + item);
            fir = false;
        }
        sw.WriteLine();
        sw.Flush();
    }
}
class pair<T, U> : IComparable<pair<T, U>> where T : IComparable<T> where U : IComparable<U>
{
    public T v1;
    public U v2;
    public pair(T v1, U v2) {
        this.v1 = v1;
        this.v2 = v2;
    }
    public int CompareTo(pair<T, U> a) { return v1.CompareTo(a.v1) != 0 ? v1.CompareTo(a.v1) : v2.CompareTo(a.v2); }
    public override string ToString() { return v1 + " " + v2; }
}
static class util
{
    public static pair<T, U> make_pair<T, U>(T v1, U v2) where T : IComparable<T> where U : IComparable<U> { return new pair<T, U>(v1, v2); }
    public static void swap<T>(ref T a, ref T b) { var t = a; a = b; b = t; }
    public static void swap<T>(this IList<T> a, int i, int j) { var t = a[i]; a[i] = a[j]; a[j] = t; }
    public static T[] copy<T>(this IList<T> a) {
        var ret = new T[a.Count];
        for (int i = 0; i < a.Count; i++) ret[i] = a[i];
        return ret;
    }
}
 
class Scan
{
    public string Str { get { return Console.ReadLine().Trim(); } }
    public string[] StrArr { get { return Str.Split(new []{' '}, System.StringSplitOptions.RemoveEmptyEntries); } }
    bool eq<T, U>() { return typeof(T).Equals(typeof(U)); }
    T ct<T, U>(U a) { return (T)Convert.ChangeType(a, typeof(T)); }
    T cv<T>(string s) { return eq<T, int>()    ? ct<T, int>(int.Parse(s))
                       : eq<T, long>()   ? ct<T, long>(long.Parse(s))
                       : eq<T, double>() ? ct<T, double>(double.Parse(s))
                       : eq<T, char>()   ? ct<T, char>(s[0])
                                         : ct<T, string>(s); }
    public void Multi<T, U>(out T a, out U b)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); }
    public void Multi<T, U, V>(out T a, out U b, out V c)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); }
    public void Multi<T, U, V, W>(out T a, out U b, out V c, out W d)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); }
    public void Multi<T, U, V, W, X>(out T a, out U b, out V c, out W d, out X e)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); e = cv<X>(ar[4]); }
    public void Multi<T, U, V, W, X, Y>(out T a, out U b, out V c, out W d, out X e, out Y f)
    { var ar = StrArr; a = cv<T>(ar[0]); b = cv<U>(ar[1]); c = cv<V>(ar[2]); d = cv<W>(ar[3]); e = cv<X>(ar[4]); f = cv<Y>(ar[5]); }
}
 
// 最小有向全域木
static class MSA
{
    class node {
        PriorityQueue<pair<long, int>> come_edges;
        long additional_cost;
 
        // init
        public node() {
            come_edges = new PriorityQueue<pair<long, int>>(){ rev = true };
            additional_cost = 0;
        }
        public void push_edge(pair<long, int> e) {
            e.v1 -= additional_cost;
            come_edges.Push(e);
        }
        public pair<long, int> pop_edge() {
            var ret = come_edges.Pop();
            ret.v1 += additional_cost;
            return ret;
        }
        public long add_cost(long ad) { return additional_cost += ad; }
        public int edge_cnt { get { return come_edges.Count; } }
 
        // hakai-teki
        public static node merge(node a, node b) {
            if (a.edge_cnt < b.edge_cnt) return merge(b, a);
            while (b.edge_cnt > 0) {
                var e = b.pop_edge();
                a.push_edge(e);
            }
            return a;
        }
    }
    public static long getmincost(List<pair<long, int>>[] edges, int root) {
        int n = edges.Length;
        var nodes = new node[n];
        for (int i = 0; i < n; i++)
        {
            nodes[i] = new node();
        }
        for (int i = 0; i < n; i++)
        {
            foreach (var item in edges[i])
                nodes[item.v2].push_edge(util.make_pair(item.v1, i));
        }
        var parent = new int[n];
        for (int i = 0; i < n; i++)
        {
            parent[i] = -1;
        }
        parent[root] = root;
        var uf_zipped = new UnionFind(n);
        var uf_connected = new UnionFind(n);
        long ret = 0;
        for (int i = 0; i < n; i++)
        {
            var st = new Stack<pair<long, int>>();
            for (int j = uf_zipped.getpar(i); parent[j] == -1; )
            {
                if (nodes[j].edge_cnt == 0) return -1;
                var e = nodes[j].pop_edge();
                e.v2 = uf_zipped.getpar(e.v2);
                if (j == e.v2) continue;
                ret += e.v1;
                nodes[j].add_cost(-e.v1);
                if (uf_connected.same(j, e.v2)) {
                    uf_zipped.unite(j, e.v2);
                    nodes[uf_zipped.getpar(j)] = node.merge(nodes[j], nodes[e.v2]);
                    j = uf_zipped.getpar(j);
                    st.Pop();
                    while (st.Any()) {
                        var ee = st.Peek();
                        ee.v2 = uf_zipped.getpar(ee.v2);
                        if (uf_zipped.getpar(ee.v2) == j) break;
 
                        st.Pop();
                        uf_zipped.unite(j, ee.v2);
                        nodes[uf_zipped.getpar(j)] = node.merge(nodes[j], nodes[ee.v2]);
                        j = uf_zipped.getpar(j);
                    }
                    parent[j] = -1;
                }
                else {
                    st.Push(e);
                    uf_connected.unite(j, e.v2);
                    parent[j] = e.v2;
                    j = e.v2;
                }
            }
        }
        return ret;
    }
}
class UnionFind
{
    int num;
    int[] par, sz, rank;
    public UnionFind(int n) {
        num = n; par = new int[n]; sz = new int[n]; rank = new int[n];
        for (int i = 0; i < n; ++i) { par[i] = i; sz[i] = 1; rank[i] = 0; }
    }
    int find(int x) { return par[x] == x ? x : (par[x] = find(par[x])); }
    public bool same(int x, int y) { return find(x) == find(y); }
    public int unionsize(int x) { return sz[find(x)]; }
    public bool unite(int x, int y) {
        x = find(x); y = find(y);
        if (x == y) return false;
        --num;
        if (rank[x] < rank[y]) {
            par[x] = y;
            sz[y] += sz[x];
        }
        else {
            par[y] = x;
            sz[x] += sz[y];
            if (rank[x] == rank[y]) ++rank[x];
        }
        return true;
    }
    public bool ispar(int x) { return x == find(x); }
    public int getpar(int x) { return find(x); }
}
 
// the greatest element pops
class PriorityQueue<T> where T : IComparable<T> {
    List<T> buf;
    public bool rev = false;
    public PriorityQueue() { buf = new List<T>(); }
    int cmp(int i, int j) { return buf[i].CompareTo(buf[j]) * (rev ? -1 : 1); }
    void swap(int i, int j) { var t = buf[i]; buf[i] = buf[j]; buf[j] = t; }
    public void Push(T elem) {
        int n = buf.Count;
        buf.Add(elem);
        while (n > 0) {
            int i = (n - 1) >> 1;
            if (cmp(n, i) > 0) swap(i, n);
            n = i;
        }
    }
    public T Pop() {
        T ret = buf[0];
        int n = buf.Count - 1;
        buf[0] = buf[n];
        buf.RemoveAt(n);
        for (int i = 0, j; (j = (i << 1) + 1) < n; i = j) {
            if (j != n - 1 && cmp(j, j + 1) < 0) ++j;
            if (cmp(i, j) < 0) swap(i, j);
        }
        return ret;
    }
    public T Top { get { return buf[0]; } }
    public int Count { get { return buf.Count; } }
}


Measured memory_bytes: 26016