using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Codeforces.TaskD
{
    public class Task
    {
        void Solve()
        {
            int n, m;
            Input.Next(out n, out m);
            var vin = new List<int>[n + 1];
            var vout = new List<int>[n + 1];
            for (var i = 1; i <= n; i++)
            {
                vin[i] = new List<int>();
                vout[i] = new List<int>();
            }

            while (m-->0)
            {
                int from, to;
                Input.Next(out from, out to);
                vin[to].Add(from);
                vout[from].Add(to);
            }

            var center = -1;
            var centerCount = 0;
            for (var i = 1; i <= n; i++)
            {
                var count = vin[i].Count + vout[i].Count;
                if (vin[i].Contains(i)) count--;
                if (count > centerCount)
                {
                    center = i;
                    centerCount = count;
                }
            }

            if (center == -1)
            {
                Console.WriteLine("Could not find center");
                center = 1;
            }

            var result = 0;

            for (var i = 1; i <= n; i++)
            {
                if (!vin[center].Contains(i))
                {
                    vin[center].Add(i);
                    vout[i].Add(center);
                    result++;
                }
                if (!vout[center].Contains(i))
                {
                    vout[center].Add(i);
                    vin[i].Add(center);
                    result++;
                }
            }

            for (var i = 1; i <= n; i++)
                if (i != center)
                {
                    while (vin[i].Count > 2)
                    {
                        var k = vin[i].Where(c => c != center).OrderByDescending(c => vout[c].Count).First();
                        vin[i].Remove(k);
                        vout[k].Remove(i);
                        result++;
                    }
                    while (vout[i].Count > 2)
                    {
                        var k = vout[i].Where(c => c != center).OrderByDescending(c => vin[c].Count).First();
                        vout[i].Remove(k);
                        vin[k].Remove(i);
                        result++;
                    }
                    if (vin[i].Count == 1 && vout[i].Count == 1)
                    {
                        vin[i].Add(i);
                        vout[i].Add(i);
                        result++;
                    }
                    if (vin[i].Count == 1)
                        result++;
                }
            Console.WriteLine(result);
        }

        public static void Main()
        {
            var task = new Task();
            try
            {
                task.Solve();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            #endif
        }
    }
}

namespace Codeforces
{
    public class Input
    {
        private static string _line;

        public static bool Next()
        {
            _line = Console.ReadLine();
            return _line != null;
        }

        public static bool Next(out long a)
        {
            var ok = Next();
            a = ok ? long.Parse(_line) : 0;
            return ok;
        }

        public static bool Next(out long a, out long b)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
            }
            else
            {
                a = b = 0;
            }

            return ok;
        }

        public static bool Next(out long a, out long b, out long c)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
            }
            else
            {
                a = b = c = 0;
            }
            return ok;
        }

        public static bool Next(out long a, out long b, out long c, out long d)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
            }
            else
            {
                a = b = c = d = 0;
            }
            return ok;
        }

        public static bool Next(out long a, out long b, out long c, out long d, out long e)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
                e = array[4];
            }
            else
            {
                a = b = c = d = e = 0;
            }
            return ok;
        }

        public static bool Next(out int a)
        {
            var ok = Next();
            a = ok ? int.Parse(_line) : 0;
            return ok;
        }

        public static bool Next(out int a, out int b)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
            }
            else
            {
                a = b = 0;
            }

            return ok;
        }

        public static bool Next(out int a, out int b, out int c)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
            }
            else
            {
                a = b = c = 0;
            }
            return ok;
        }

        public static bool Next(out int a, out int b, out int c, out int d)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
            }
            else
            {
                a = b = c = d = 0;
            }
            return ok;
        }

        public static bool Next(out int a, out int b, out int c, out int d, out int e)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
                e = array[4];
            }
            else
            {
                a = b = c = d = e = 0;
            }
            return ok;
        }

        public static bool Next(out int a, out int b, out int c, out int d, out int e, out int f)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
                e = array[4];
                f = array[5];
            }
            else
            {
                a = b = c = d = e = f = 0;
            }
            return ok;
        }

        public static IEnumerable<long> ArrayLong()
        {
            return !Next() ? new List<long>() : _line.Split().Select(long.Parse);
        }

        public static IEnumerable<int> ArrayInt()
        {
            return !Next() ? new List<int>() : _line.Split().Select(int.Parse);
        }

        public static bool Next(out string value)
        {
            value = string.Empty;
            if (!Next()) return false;
            value = _line;
            return true;
        }
    }

    public class DisjointSet
    {
        private readonly int[] _parent;
        private readonly int[] _rank;
        public int Count { get; private set; }

        public DisjointSet(int count, int initialize = 0)
        {
            Count = count;
            _parent = new int[Count];
            _rank = new int[Count];
            for (var i = 0; i < initialize; i++) _parent[i] = i;
        }

        private DisjointSet(int count, int[] parent, int[] rank)
        {
            Count = count;
            _parent = parent;
            _rank = rank;
        }

        public void Add(int v)
        {
            _parent[v] = v;
            _rank[v] = 0;
        }

        public int Find_Recursive(int v)
        {
            if (_parent[v] == v) return v;
            return _parent[v] = Find(_parent[v]);
        }

        public int Find(int v)
        {
            if (_parent[v] == v) return v;
            var last = v;
            while (_parent[last] != last) last = _parent[last];
            while (_parent[v] != v)
            {
                var t = _parent[v];
                _parent[v] = last;
                v = t;
            }
            return last;
        }

        public int this[int v]
        {
            get { return Find(v); }
            set { Union(v, value); }
        }

        public void Union(int a, int b)
        {
            a = Find(a);
            b = Find(b);
            if (a == b) return;
            if (_rank[a] < _rank[b])
            {
                var t = _rank[a];
                _rank[a] = _rank[b];
                _rank[b] = t;
            }
            _parent[b] = a;
            if (_rank[a] == _rank[b]) _rank[a]++;
        }

        public int GetSetCount()
        {
            var result = 0;
            for (var i = 0; i < Count; i++)
            {
                if (_parent[i] == i) result++;
            }
            return result;
        }

        public DisjointSet Clone()
        {
            var rank = new int[Count];
            _rank.CopyTo(rank, 0);
            var parent = new int[Count];
            _parent.CopyTo(parent, 0);
            return new DisjointSet(Count, parent, rank);
        }

        public override string ToString()
        {
            return string.Join(",", _parent.Take(50));
        }
    }

    public class Matrix
    {
        public static Matrix Create(int i, int j)
        {
            var m = new Matrix(i, j);
            return m;
        }

        public static Matrix Create(int i)
        {
            var m = new Matrix(i, i);
            return m;
        }

        public long Modulo { get; set; }

        private readonly int _width;
        private readonly int _height;
        private readonly long[,] _data;
        public int Width { get { return _width; } }
        public int Height { get { return _height; } }

        private Matrix(int i, int j)
        {
            Modulo = 1000000000000000000L;
            _width = j;
            _height = i;
            _data = new long[_height, _width];
        }

        public static Matrix operator *(Matrix m1, Matrix m2)
        {
            if (m1.Width != m2.Height) throw new InvalidDataException("m1.Width != m2.Height");
            var m = Create(m2.Width, m1.Height);
            m.Modulo = m1.Modulo;
            for (var i = 0; i < m2.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                {
                    for (var k = 0; k < m1.Width; k++)
                        m[j, i] += (m1[j, k] * m2[k, i]) % m1.Modulo;
                    m[j, i] %= m1.Modulo;
                }
            return m;
        }

        public static Matrix operator +(Matrix m1, Matrix m2)
        {
            var m = m1.Clone();
            for (var i = 0; i < m2.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                    m[j, i] = (m[j, i] + m2[j, i]) % m1.Modulo;
            return m;
        }

        public static Matrix operator -(Matrix m1, Matrix m2)
        {
            var m = m1.Clone();
            for (var i = 0; i < m2.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                    m[j, i] = (m[j, i] - m2[j, i]) % m1.Modulo;
            return m;
        }

        public static Matrix operator *(Matrix m1, long l)
        {
            var m = m1.Clone();
            for (var i = 0; i < m1.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                    m[j, i] = (m[j, i] * l) % m.Modulo;
            return m;
        }

        public static Matrix operator *(long l, Matrix m1)
        {
            return m1 * l;
        }

        public static Matrix operator +(Matrix m1, long l)
        {
            var m = m1.Clone();
            for (var i = 0; i < m1.Width; i++)
                m[i, i] = (m[i, i] + l) % m.Modulo;
            return m;
        }

        public static Matrix operator +(long l, Matrix m1)
        {
            return m1 + l;
        }

        public static Matrix operator -(Matrix m1, long l)
        {
            return m1 + (-l);
        }

        public static Matrix operator -(long l, Matrix m1)
        {
            var m = m1.Clone() * -1;
            return m + l;
        }

        public Matrix BinPower(long l)
        {
            var n = 1;
            var m = Clone();
            var result = new Matrix(m.Height, m.Width) + 1;
            result.Modulo = m.Modulo;
            while (l != 0)
            {
                var i = l & ~(l - 1);
                l -= i;
                while (n < i)
                {
                    m = m * m;
                    n <<= 1;
                }
                result *= m;
            }
            return result;
        }

        public void Fill(long l)
        {
            l %= Modulo;
            for (var i = 0; i < _height; i++)
                for (var j = 0; j < _width; j++)
                    _data[i, j] = l;
        }

        public Matrix Clone()
        {
            var m = new Matrix(_width, _height);
            Array.Copy(_data, m._data, _data.Length);
            m.Modulo = Modulo;
            return m;
        }

        public long this[int i, int j]
        {
            get { return _data[i, j]; }
            set { _data[i, j] = value % Modulo; }
        }
    }

    public class RedBlackTree<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
    {
        private readonly List<Node> _items = new List<Node>();
        private Node _root;
        private readonly IComparer<TKey> _comparer;

        public RedBlackTree()
        {
            _comparer = Comparer<TKey>.Default;
        }

        private Node _search(TKey key)
        {
            var node = _root;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return node;
                node = i > 0 ? node.Right : node.Left;
            }
            return null;
        }

        public void Add(TKey key, TValue value)
        {
            var node = new Node { Key = key, Value = value, Red = true };
            _items.Add(node);
            if (_root == null)
            {
                _root = node;
                _root.Red = false;
                return;
            }
            var x = _root;
            Node y = null;
            while (x != null)
            {
                y = x;
                x = _comparer.Compare(key, x.Key) > 0 ? x.Right : x.Left;
            }
            node.Parent = y;
            if (y == null) _root = node;
            else if (_comparer.Compare(key, y.Key) > 0) y.Right = node;
            else y.Left = node;
            InsertFixup(node);
        }

        private void InsertFixup(Node node)
        {
            while (true)
            {
                var parent = node.Parent;
                if (parent == null || !parent.Red || parent.Parent == null) break;
                var grand = parent.Parent;

                if (parent == grand.Left)
                {
                    var uncle = grand.Right;
                    if (uncle != null && uncle.Red) /* parent and uncle both red: we could swap colors of them with grand */
                    {
                        parent.Red = false;
                        uncle.Red = false;
                        grand.Red = true;
                        node = grand; /* and continue fixing tree for grand */
                    }
                    else if (node == parent.Right) /* we rotate around the parent */
                    {
                        node = parent;
                        RotateLeft(node);
                    }
                    else /* rotate around grand and switch colors of grand and parent */
                    {
                        parent.Red = false;
                        grand.Red = true;
                        RotateRight(grand);
                        if (grand == _root) _root = parent;
                        break; /* and finish since tree is fixed */
                    }
                }
                else
                {
                    if (_root.Parent != null) Debugger.Break();

                    var uncle = grand.Left;
                    if (uncle != null && uncle.Red) /* parent and uncle both red: we could swap colors of them with grand */
                    {
                        parent.Red = false;
                        uncle.Red = false;
                        grand.Red = true;
                        node = grand; /* and continue fixing tree for grand */
                    }
                    else if (node == parent.Left) /* we rotate around the parent */
                    {
                        node = parent;
                        RotateRight(node);
                    }
                    else /* rotate around grand and switch colors of grand and parent */
                    {
                        parent.Red = false;
                        grand.Red = true;
                        RotateLeft(grand);
                        if (grand == _root) _root = parent;
                        break; /* and finish since tree is fixed */
                    }
                }
            }
            _root.Red = false;
        }

        private void RotateLeft(Node node)
        {
            if (node.Right == null)
                throw new NotSupportedException("Cannot rotate left: right node is missing");
            var parent = node.Parent;
            var right = node.Right;
            right.Parent = parent;
            if (parent != null)
            {
                if (parent.Left == node) parent.Left = right;
                else parent.Right = right;
            }
            node.Right = right.Left;
            if (node.Right != null)
                node.Right.Parent = node;
            right.Left = node;
            node.Parent = right;
        }

        private void RotateRight(Node node)
        {
            if (node.Left == null)
                throw new NotSupportedException("Cannot rotate right: left node is missing");
            var parent = node.Parent;
            var left = node.Left;
            left.Parent = parent;
            if (parent != null)
            {
                if (parent.Left == node) parent.Left = left;
                else parent.Right = left;
            }
            node.Left = left.Right;
            if (node.Left != null)
                node.Left.Parent = node;
            left.Right = node;
            node.Parent = left;
        }

        public void Remove(TKey key)
        {
            var node = _search(key);
            if (node == null) return;

            var deleted = node.Left == null || node.Right == null ? node : Next(node);
            var child = deleted.Left ?? deleted.Right;
            if (child != null)
                child.Parent = deleted.Parent;
            if (deleted.Parent == null) /* root */
                _root = child;
            else if (deleted == deleted.Parent.Left)
                deleted.Parent.Left = child;
            else
                deleted.Parent.Right = child;
            if (node != deleted)
            {
                node.Key = deleted.Key;
                node.Value = deleted.Value;
            }

            if (!deleted.Red)
            {
                DeleteFixup(child, deleted.Parent);
            }
        }

        private void DeleteFixup(Node node, Node parent)
        {
            while (parent != null && (node == null || !node.Red))
            {
                if (node == parent.Left)
                {
                    var brother = parent.Right;
                    if (brother.Red)
                    {
                        brother.Red = false;
                        parent.Red = true;
                        RotateLeft(parent);
                        brother = parent.Right;
                    }
                    if ((brother.Left == null || !brother.Left.Red) && (brother.Right == null || !brother.Right.Red))
                    {
                        node = parent.Red ? _root : parent;
                        brother.Red = true;
                        parent.Red = false;
                    }
                    else
                    {
                        if (brother.Right == null || !brother.Right.Red)
                        {
                            if (brother.Left != null)
                                brother.Left.Red = false;
                            brother.Red = true;
                            RotateRight(brother);
                            brother = parent.Right;
                        }
                        if (!brother.Right.Red) Debugger.Break();
                        brother.Red = parent.Red;
                        parent.Red = false;
                        if (brother.Right != null)
                            brother.Right.Red = false;
                        RotateLeft(parent);
                        node = _root;
                    }
                }
                else
                {
                    var brother = parent.Left;
                    if (brother.Red)
                    {
                        brother.Red = false;
                        parent.Red = true;
                        RotateRight(parent);
                        brother = parent.Left;
                    }
                    if ((brother.Right == null || !brother.Right.Red) && (brother.Left == null || !brother.Left.Red))
                    {
                        node = parent.Red ? _root : parent;
                        brother.Red = true;
                        parent.Red = false;
                    }
                    else
                    {
                        if (brother.Left == null || !brother.Left.Red)
                        {
                            if (brother.Right != null)
                                brother.Right.Red = false;
                            brother.Red = true;
                            RotateLeft(brother);
                            brother = parent.Left;
                        }
                        brother.Red = parent.Red;
                        parent.Red = false;
                        if (brother.Left != null)
                            brother.Left.Red = false;
                        RotateRight(parent);
                        node = _root;
                    }
                }
                parent = node.Parent;
            }

            node.Red = false;
        }

        public TValue this[TKey key]
        {
            get
            {
                var node = _search(key);
                return node == null ? default(TValue) : node.Value;
            }
            set
            {
                var node = _search(key);
                if (node == null) Add(key, value);
                else node.Value = value;
            }
        }

        public bool Check()
        {
            int count;
            return _root == null || _root.Check(out count);
        }

        private Node Minimum(Node node)
        {
            var result = node;
            while (result.Left != null) result = result.Left;
            return result;
        }

        private Node Maximum(Node node)
        {
            var result = node;
            while (result.Right != null) result = result.Right;
            return result;
        }

        private Node Next(Node node)
        {
            Node result;
            if (node.Right != null)
            {
                result = Minimum(node.Right);
            }
            else
            {
                while (node.Parent != null && node.Parent.Right == node)
                    node = node.Parent;
                result = node.Parent;
            }
            return result;
        }

        private Node Previous(Node node)
        {
            Node result;
            if (node.Left != null)
            {
                result = Maximum(node.Left);
            }
            else
            {
                while (node.Parent != null && node.Parent.Left == node)
                    node = node.Parent;
                result = node.Parent;
            }
            return result;
        }

        public void Print()
        {
            var node = Minimum(_root);
            while (node != null)
            {
                Console.Write(node.Red ? '*' : ' ');
                Console.Write(node.Key);
                Console.Write('\t');
                node = Next(node);
            }
        }

        #region Nested classes

        [DebuggerDisplay("{ToString()}")]
        private sealed class Node
        {
            public TKey Key;
            public TValue Value;
            public bool Red;

            public Node Parent;
            public Node Left;
            public Node Right;

            public bool Check(out int count)
            {
                count = 0;
                if (Red)
                {
                    if (Left != null && Left.Red) return false;
                    if (Right != null && Right.Red) return false;
                }
                var left = 0;
                var right = 0;
                if (Left != null && !Left.Check(out left)) return false;
                if (Right != null && !Right.Check(out right)) return false;
                count = left + (Red ? 0 : 1);
                if (left != right)
                {
                    ;
                }
                return left == right;
            }

            public override string ToString()
            {
                return ToShortString(2);
            }

            private string ToShortString(int depth = 0)
            {
                return depth == 0
                    ? string.Format("{0}{1}", Red ? "*" : "", Key)
                    : string.Format("({1}<{0}>{2})", ToShortString(), Left == null ? "null" : Left.ToShortString(depth - 1), Right == null ? "null" : Right.ToShortString(depth - 1));
            }
        }

        #endregion

        #region IEnumerable

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }

    /// <summary>
    /// Prime numbers
    /// </summary>
    public class Primes
    {
        /// <summary>
        /// Returns prime numbers in O(n)
        /// Returns lowet divisors as well
        /// Memory O(n)
        /// </summary>
        public static void ImprovedSieveOfEratosthenes(int n, out int[] lp, out List<int> pr)
        {
            lp = new int[n];
            pr = new List<int>();
            for (var i = 2; i < n; i++)
            {
                if (lp[i] == 0)
                {
                    lp[i] = i;
                    pr.Add(i);
                }
                foreach (var prJ in pr)
                {
                    var prIj = i * prJ;
                    if (prJ <= lp[i] && prIj <= n - 1)
                    {
                        lp[prIj] = prJ;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Returns prime numbers in O(n*n)
        /// </summary>
        public static void SieveOfEratosthenes(int n, out List<int> pr)
        {
            var m = 50000;//(int)(3l*n/(long)Math.Log(n)/2);
            pr = new List<int>();
            var f = new bool[m];
            for (var i = 2; i * i <= n; i++)
                if (!f[i])
                    for (var j = (long)i * i; j < m && j * j < n; j += i)
                        f[j] = true;
            pr.Add(2);
            for (var i = 3; i * i <= n; i += 2)
                if (!f[i])
                    pr.Add(i);
        }

        /// <summary>
        /// Greatest common divisor
        /// </summary>
        public static int Gcd(int x, int y)
        {
            while (y != 0)
            {
                var c = y;
                y = x % y;
                x = c;
            }
            return x;
        }

        /// <summary>
        /// Greatest common divisor
        /// </summary>
        public static long Gcd(long x, long y)
        {
            while (y != 0)
            {
                var c = y;
                y = x % y;
                x = c;
            }
            return x;
        }

        /// <summary>
        /// Greatest common divisor
        /// </summary>
        public static BigInteger Gcd(BigInteger x, BigInteger y)
        {
            while (y != 0)
            {
                var c = y;
                y = x % y;
                x = c;
            }
            return x;
        }

        /// <summary>
        /// Returns all divisors of n in O(√n)
        /// </summary>
        public static IEnumerable<long> GetDivisors(long n)
        {
            long r;
            while (true)
            {
                var x = Math.DivRem(n, 2, out r);
                if (r != 0) break;
                n = x;
                yield return 2;
            }
            var i = 3;
            while (i <= Math.Sqrt(n))
            {
                var x = Math.DivRem(n, i, out r);
                if (r == 0)
                {
                    n = x;
                    yield return i;
                }
                else i += 2;
            }
            if (n != 1) yield return n;
        }
    }

}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;

// (づ°ω°)づﾐ★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    static class Kuhn
    {
        private static List<int>[] g;
        private static int[] match;

        static bool Dfs(int x, bool[] f, int z)
        {
            if (f[x] || x == z)
                return false;
            f[x] = true;
            foreach (int e in g[x])
                if (e != z && (match[e] == -1 || Dfs(match[e], f, z)))
                {
                    match[e] = x;
                    return true;
                }
            return false;
        }

        public static int[] Match(List<int>[] g, int m, int z)
        {
            Kuhn.g = g;
            match = Enumerable.Repeat(-1, m).ToArray();
            for (int i = 0; i < g.Length; i++)
                Dfs(i, new bool[g.Length], z);
            return match;
        }
    }

    public void Solve()
    {
        int n = ReadInt();
        int m = ReadInt();
        var g = Enumerable.Repeat(0, n).Select(x => new List<int>()).ToArray();
        for (int i = 0; i < m; i++)
        {
            int u = ReadInt() - 1;
            int v = ReadInt() - 1;
            g[u].Add(v);
        }

        int ans = int.MaxValue;
        for (int i = 0; i < n; i++)
        {
            int s = 2 * n - 1 - g[i].Count;
            for (int j = 0; j < n; j++)
                if (j != i)
                    foreach (int e in g[j])
                        if (e == i)
                            s--;

            int match = Kuhn.Match(g, n, i).Count(mm => mm > -1);
            int x = m - 2 * n + 1 + s;
            s += x - 2 * match + n - 1;
            ans = Math.Min(ans, s);
        }
        Write(ans);
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;

    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("game.in");
        //writer = new StreamWriter("game.out");
#endif
        try
        {
            var thread = new Thread(new Solver().Solve, 1024 * 1024 * 256);
            thread.Start();
            thread.Join();
            //new Solver().Solve();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            Console.WriteLine(ex);
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write

    private static Queue<string> currentLineTokens = new Queue<string>();

    private static string[] ReadAndSplitLine()
    {
        return reader.ReadLine().Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
    }

    public static string ReadToken()
    {
        while (currentLineTokens.Count == 0)
            currentLineTokens = new Queue<string>(ReadAndSplitLine());
        return currentLineTokens.Dequeue();
    }

    public static int ReadInt()
    {
        return int.Parse(ReadToken());
    }

    public static long ReadLong()
    {
        return long.Parse(ReadToken());
    }

    public static double ReadDouble()
    {
        return double.Parse(ReadToken(), CultureInfo.InvariantCulture);
    }

    public static int[] ReadIntArray()
    {
        return ReadAndSplitLine().Select(int.Parse).ToArray();
    }

    public static long[] ReadLongArray()
    {
        return ReadAndSplitLine().Select(long.Parse).ToArray();
    }

    public static double[] ReadDoubleArray()
    {
        return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray();
    }

    public static int[][] ReadIntMatrix(int numberOfRows)
    {
        int[][] matrix = new int[numberOfRows][];
        for (int i = 0; i < numberOfRows; i++)
            matrix[i] = ReadIntArray();
        return matrix;
    }

    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows);
        int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++)
        {
            ret[i] = new int[numberOfRows];
            for (int j = 0; j < numberOfRows; j++)
                ret[i][j] = matrix[j][i];
        }
        return ret;
    }

    public static string[] ReadLines(int quantity)
    {
        string[] lines = new string[quantity];
        for (int i = 0; i < quantity; i++)
            lines[i] = reader.ReadLine().Trim();
        return lines;
    }

    public static void WriteArray<T>(IEnumerable<T> array)
    {
        writer.WriteLine(string.Join(" ", array));
    }

    public static void Write(params object[] array)
    {
        WriteArray(array);
    }

    public static void WriteLines<T>(IEnumerable<T> array)
    {
        foreach (var a in array)
            writer.WriteLine(a);
    }

    #endregion
}


#include<stdio.h>
#include<algorithm>
#include<vector>
#include<string.h>
#define For(i,n) for(int i=1; i<=n; i++)
#define Rep(i,n) for(int i=0; i<n; i++)
#define N 500
#define M 1000

using namespace std;

struct Edge{
  int u,v;
}e[M+10];
vector<int> adj[N+10];
int vis[N+10],mark[N+10];
int match(int u){
  if(vis[u])return 0;
  vis[u]=1;
  Rep(i,adj[u].size()){
    if(!mark[adj[u][i]]||match(mark[adj[u][i]])){
      mark[adj[u][i]]=u;
      return 1;
    }
  }
  return 0;
}
int n,m;
int main(){
#ifndef ONLINE_JUDGE
  freopen("in.txt","r",stdin);
#endif
  scanf("%d%d",&n,&m);
  For(i,m){
    scanf("%d%d",&e[i].u,&e[i].v);
  }
  int ans=1<<30;
  For(i,n){
    int cur=n+n-1+n-1;
    For(j,n)adj[j].clear();
    For(j,m){
      if(e[j].u!=i&&e[j].v!=i)
	adj[e[j].u].push_back(e[j].v);
      else
	cur--;
    }
    memset(mark,0,sizeof(mark));
    For(j,n)if(j!=i){
      cur+=adj[j].size();
      memset(vis,0,sizeof(vis));
      cur-=2*match(j);
    }
    ans=min(ans,cur);
  }
  printf("%d",ans);
  return 0;
}


#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<bitset>
#include<functional>
using namespace std;
#define KeyTree root->ch[1]->ch[0]
typedef long long LL;
typedef pair<int,int>PII;
const int mod = 10007;
const int maxn = 511;
const int base = 1000;
const int INF = (int)(0x7f7f7f7f);
const double pi = acos(-1.0);
const double inf = 1e20;
vector<int>edge[maxn];
bool vis[maxn];
int cx[maxn],cy[maxn];
bool G[maxn][maxn];
int g[maxn][maxn];
bool dfs(int u){
    if(vis[u])
        return false;
    vis[u]=true;
    vector<int>::iterator it;
    for(it=edge[u].begin();it!=edge[u].end();++it){
        int v=*it;
        if(!cy[v]||dfs(cy[v])){
            cy[v]=u;
            return true;
        }
    }
    return false;
}
int A[2111],B[2111];
int solve(int n,int m,int k){
    int i,j,ans=0;
    for(i=1;i<=n;++i){
        edge[i].clear();
    }
    int add=n-1+2*(n-1)+1;
    int del=0;
    for(i=0;i<m;++i){
        if(A[i]==k||B[i]==k){
            --add;
        }else{
            ++del;
            edge[A[i]].push_back(B[i]);
          //  edge[B[i]].push_back(A[i]);
        }
    }
    int tmp=0;
    memset(cy,0,sizeof(cy));
    for(i=1;i<=n;++i){
        memset(vis,false,sizeof(vis));
        tmp+=dfs(i);
    }
    ans=del-tmp+add-tmp;
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
   freopen("in.txt","r",stdin);
#endif
   int n,m,u,v,i;
   cin>>n>>m;
   for(i=0;i<m;++i){
       cin>>A[i]>>B[i];
   }
   int ans=11111111;
   for(i=1;i<=n;++i){
       ans=min(ans,solve(n,m,i));
   }
   cout<<ans<<endl;
   return 0;
}


#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<bitset>
#include<functional>
using namespace std;
#define KeyTree root->ch[1]->ch[0]
typedef long long LL;
typedef pair<int,int>PII;
const int mod = 10007;
const int maxn = 511;
const int base = 1000;
const int INF = (int)(0x7f7f7f7f);
const double pi = acos(-1.0);
const double inf = 1e20;
vector<int>edge[maxn];
bool vis[maxn];
int cx[maxn],cy[maxn];
bool G[maxn][maxn];
int g[maxn][maxn];
bool dfs(int u){
    if(vis[u])
        return false;
    vis[u]=true;
    vector<int>::iterator it;
    for(it=edge[u].begin();it!=edge[u].end();++it){
        int v=*it;
        if(!cy[v]||dfs(cy[v])){
            cy[v]=u;
            return true;
        }
    }
    return false;
}
int A[2111],B[2111];
int solve(int n,int m,int k){
    int i,j,ans=0;
    for(i=1;i<=n;++i){
        edge[i].clear();
    }
    int add=n-1+2*(n-1)+1;
    int del=0;
    for(i=0;i<m;++i){
        if(A[i]==k||B[i]==k){
            --add;
        }else{
            ++del;
            edge[A[i]].push_back(B[i]);
            edge[B[i]].push_back(A[i]);
        }
    }
    int tmp=0;
    memset(cy,0,sizeof(cy));
    for(i=1;i<=n;++i){
        memset(vis,false,sizeof(vis));
        tmp+=dfs(i);
    }
    ans=del-tmp+add-tmp;
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
   freopen("in.txt","r",stdin);
#endif
   int n,m,u,v,i;
   cin>>n>>m;
   for(i=0;i<m;++i){
       cin>>A[i]>>B[i];
   }
   int ans=11111111;
   for(i=1;i<=n;++i){
       ans=min(ans,solve(n,m,i));
   }
   cout<<ans<<endl;
   return 0;
}


#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<algorithm>
#include<vector>
#include<iostream>
#include<bitset>
#include<functional>
using namespace std;
#define KeyTree root->ch[1]->ch[0]
typedef long long LL;
typedef pair<int,int>PII;
const int mod = 10007;
const int maxn = 511;
const int base = 1000;
const int INF = (int)(0x7f7f7f7f);
const double pi = acos(-1.0);
const double inf = 1e20;
vector<int>edge[maxn];
bool vis[maxn];
int cx[maxn],cy[maxn];
bool G[maxn][maxn];
int g[maxn][maxn];
bool dfs(int u){
    if(vis[u])
        return false;
    vis[u]=true;
    vector<int>::iterator it;
    for(it=edge[u].begin();it!=edge[u].end();++it){
        int v=*it;
        if(!cy[v]||dfs(cy[v])){
            cy[v]=u;
            return true;
        }
    }
    return false;
}
int A[2111],B[maxn];
int solve(int n,int m,int k){
    int i,j,ans=0;
    for(i=1;i<=n;++i){
        edge[i].clear();
    }
    int add=n-1+2*(n-1)+1;
    int del=0;
    for(i=0;i<m;++i){
        if(A[i]==k||B[i]==k){
            --add;
        }else{
            ++del;
            edge[A[i]].push_back(B[i]);
            edge[B[i]].push_back(A[i]);
        }
    }
    int tmp=0;
    memset(cy,0,sizeof(cy));
    for(i=1;i<=n;++i){
        memset(vis,false,sizeof(vis));
        tmp+=dfs(i);
    }
    ans=del-tmp+add-tmp;
    return ans;
}
int main(){
    ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
   freopen("in.txt","r",stdin);
#endif
   int n,m,u,v,i;
   cin>>n>>m;
   for(i=0;i<m;++i){
       cin>>A[i]>>B[i];
   }
   int ans=11111111;
   for(i=1;i<=n;++i){
       ans=min(ans,solve(n,m,i));
   }
   cout<<ans<<endl;
   return 0;
}


// Alfonso2 Peterssen (mukel)
#include <bits/stdc++.h>
using namespace std;
#define endl ('\n')

template<typename T> struct number_iterator:iterator<random_access_iterator_tag, T>{T v;number_iterator(T v):v(v){}operator T&(){return v;}T operator *(){return v;}};
template<typename T> struct number_range{T b,e;number_range(T b, T e):b(b),e(e){}number_iterator<T> begin(){return b;}number_iterator<T> end(){return e;}};
/* inclusive */template<typename T> number_range<T> range(T b,T e){return number_range<T>(b, e + 1);}
template<typename T> number_range<T> range(T e){return number_range<T>(0, e);}

const int
    MAXV = 505;

int V, E;
int center;
int M[MAXV][MAXV];
vector< int > G[MAXV];

int curMark;
int mark[MAXV];
int from[MAXV];

bool dfs(int u)
{
    if (mark[u] == curMark)
        return false;

    mark[u] = curMark;

    for (int v: G[u]) if (v != center)
        if (from[v] < 0 || dfs(from[v]))
        {
            from[v] = u;
            return true;
        }

    return false;
}

int solve()
{
    int used = 0;

    memset(from, -1, sizeof(from));

    for (int u: range(V)) if (u != center)
    {
        curMark++;
        if (dfs(u)) used++;
    }

    int toAdd = 0;
    int toRemove = 0;

    for (int u: range(V))
    {
        if (!M[u][center]) toAdd++;

        if (u != center)
        {
            if (!M[center][u]) toAdd++;

            for (int v: range(V)) if (v != center)
                if (M[u][v] && from[v] != u) toRemove++;
        }
    }

    //cout << toAdd << " " << toRemove << " "<< used << endl;

    return toAdd + toRemove + V - 1 - used;
}

int main(int argc, char* argv[])
{
    if (argc > 1) freopen(argv[1], "r", stdin);
    if (argc > 2) freopen(argv[2], "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);

    cin >> V >> E;

    for (int i: range(E))
    {
        int u, v;
        cin >> u >> v;
        --u;
        --v;
        M[u][v] = true;
        G[u].push_back(v);
    }

/*
    center = 2;
    cout << solve() << endl;
    return 0;
*/
    int ans = 1000000;
    for (center = 0; center < V; ++center)
    {
        ans = min(ans, solve());
    }

    cout << ans << endl;

    return 0;
}


// Paste me into the FileEdit configuration dialog
#include <algorithm>
#include <functional>

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <vector>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

typedef long long ll;
#define FOR(i,a,b) for(int i = (a); i < (b); ++i)
#define mp make_pair
#define pb push_back
#define sz(s) (int)((s).size())
#define MAX 555

int G[MAX][MAX], H[MAX][MAX];
int bio[MAX], matched[MAX];
int n,m;

int dfs(int node) {
  if(bio[node]) return 0;
  bio[node] = 1;
  for(int i = 0; i < n; ++i) {
    if(!H[node][i]) continue;
    if(matched[i] == -1 || dfs(matched[i])) {
      matched[i] = node;
      return 1;
    }
  }
  return 0;
}

int main() {
  scanf("%d %d", &n, &m);
  FOR(i, 0, m) {
    int a, b;
    scanf("%d %d", &a, &b);
    G[a - 1][b - 1] = 1;
  }

  int ret = MAX * MAX;
  FOR(source, 0, n) {
    FOR(i, 0, n)
      FOR(j, 0, n)
      H[i][j] = G[i][j];

    int withs = 0;
    if(G[source][source]) withs--;
    FOR(i, 0, n) {
      withs += G[i][source] + G[source][i];
      H[i][source] = 0; H[source][i] = 0;
    }

    vector<int> left, right;
    FOR(i, 0, n)
      FOR(j, 0, n)
      if(H[i][j]) {
	left.pb(i);
      }

    sort(left.begin(), left.end());
    left.erase(unique(left.begin(), left.end()), left.end());

    memset(matched, -1, sizeof matched);
    int t = 0;
    for(int i = 0; i < sz(left); ++i) {
      memset(bio, 0, sizeof bio);
      t += dfs(left[i]);
    }

    ret = min(ret, 2 * n - 1 - withs + m - withs - t + n - 1 - t);
  }

  printf("%d\n", ret);
  return 0;
}


/**
 *
 * rais.fathin38
 */

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cassert>
#include <cstdlib>
#include <cctype>
#include <ctime>

#include <iostream>
#include <iomanip>
#include <sstream>
#include <numeric>
#include <utility>
#include <string>
#include <algorithm>
#include <vector>
#include <map>
#include <queue>
#include <set>
#include <list>
#include <bitset>
#include <complex>

using namespace std;

#define ALL(a) a.begin(), a.end()
#define SZ(a) ((int)a.size())

#define MIN(a, b) a = min(a, b)
#define MAX(a, b) a = max(a, b)

#define SHOW(x) { cerr << ">>> " << #x << " : " << x << endl; }

#define pb push_back
#define mp make_pair
#define fi first
#define se second

typedef long long LL;
typedef pair<int, int> pii;

const int N = 501;

int n, m;
int owner[N];
bool old[N][N];
vector<int> adj[N];
bitset<N*2> visit;

int match(int u) {
  if (visit[u]) return 0;
  visit[u] = true;
  for (int &v : adj[u]) {
    if (owner[v-n] == -1 || match(owner[v-n])) {
      owner[v-n] = u;
      return 1;
    }
  }
  return 0;
}

int solve(int center) {
  for (int i = 0; i < n; i++) adj[i].clear();
  int cnt = 0;
  for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++) if (old[i][j]) {
      if (i != center && j != center) adj[i].pb(j+n);
      else cnt++;
    }
  int matching = 0;
  for (int i = 0; i < n; i++) owner[i] = -1;
  for (int i = 0; i < n; i++) {
    visit.reset();
    matching += match(i);
  }
  return (2*n - 1 - cnt) + (n - 1 - matching) + (m - cnt - matching);
}

int main() {
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int u, v; cin >> u >> v;
    u--; v--;
    old[u][v] = true;
  }
  int ans = (int)1e9;
  for (int center = 0; center < n; center++) {
    MIN(ans, solve(center));
  }
  cout << ans << endl;
  return 0;
}


#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <cfloat>
#include <ctime>
#include <cassert>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>
#include <list>
#include <iomanip>
#include <fstream>
#include <bitset>

#ifdef LOCAL
#include "local.h"
#endif

using namespace std;

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define all(a) (a).begin(), (a).end()
#define clr(a, x) memset(a, x, sizeof(a))
#define sz(a) ((int)(a).size())
#define mp(a, b) make_pair(a, b)
#define ten(n) ((long long)(1e##n))

template <typename T, typename U> void upmin(T& a, const U& b) { a = min<T>(a, b); }
template <typename T, typename U> void upmax(T& a, const U& b) { a = max<T>(a, b); }
template <typename T> void uniq(T& a) { sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); }
template <class T> string to_s(const T& a) { ostringstream os; os << a; return os.str(); }
template <class T> T to_T(const string& s) { istringstream is(s); T res; is >> res; return res; }
void fast_io() { cin.tie(0); ios::sync_with_stdio(false); }
bool in_rect(int x, int y, int w, int h) { return 0 <= x && x < w && 0 <= y && y < h; }

typedef long long ll;
typedef pair<int, int> pint;

const int dx[] = { 0, 1, 0, -1 };
const int dy[] = { 1, 0, -1, 0 };

class BipatiteGraph
{
    vector<bool> used;

    bool _dfs(int v)
    {
        used[v] = true;
        for (int i = 0; i < (int)edges[v].size(); ++i)
        {
            int u = edges[v][i];
            int k = match[u];
            if (k < 0 || (!used[k] && _dfs(k)))
            {
                match[v] = u;
                match[u] = v;
                return true;
            }
        }
        return false;
    }

public:
    int n, m;
    int vertices;
    vector<vector<int> > edges;
    vector<int> match;
    int matching;

    BipatiteGraph(int n, int m)
        : used(n + m), n(n), m(m), vertices(n + m), edges(n + m), match(n + m), matching(0)
    {
        clear();
    }

    void add_edge(int a, int b)
    {
        edges[a].push_back(b + n);
        edges[b + n].push_back(a);
    }

    void clear()
    {
        fill(match.begin(), match.end(), -1);
        matching = 0;
    }

    bool dfs(int v)
    {
        fill(used.begin(), used.end(), false);
        return _dfs(v);
    }

    int update_matching()
    {
        for (int i = 0; i < n; ++i)
            if (match[i] < 0 && dfs(i))
                ++matching;
        return matching;
    }

    int max_matching()
    {
        fill(match.begin(), match.end(), -1);
        int res = 0;
        for (int i = 0; i < n; ++i)
        {
            if (match[i] < 0)
            {
                if (dfs(i))
                    ++res;
            }
        }
        return res;
    }

    vector<pair<int, int> > matching_edges()
    {
        max_matching();
        vector<pair<int, int> > edges;
        for (int i = 0; i < n; ++i)
            if (match[i] >= 0)
                edges.push_back(make_pair(i, match[i] - n));
        return edges;
    }
};
int main()
{
    int n, m;
    cin >> n >> m;
    int u[1024], v[1024];
    rep(i, m)
        cin >> u[i] >> v[i], --u[i], --v[i];

    int res = ten(9);
    rep(center, n)
    {
        BipatiteGraph g(n, n);
        int changes = 2 * n - 1;
        int edges = 0;
        rep(i, m)
        {
            if (u[i] == center || v[i] == center)
                --changes;
            else
            {
                g.add_edge(u[i], v[i]);
                ++edges;
            }
        }

        int unchange = g.max_matching();
        changes += ((n - 1) - unchange) + (edges - unchange);
        upmin(res, changes);
    }
    cout << res << endl;
}


#include <bits/extc++.h>
#include <iostream>

using namespace std;

//#define NDEBUG
#ifdef NDEBUG
#define DEBUG if (false)
#else
#define DEBUG if (true)
#endif
#define WRITE(x) DEBUG { cout << (x) << endl; }
#define WATCH(x) DEBUG { cout << #x << " = " << (x) << endl; }
#define ALL(x) (x).begin(), (x).end()
//#define FORN(i, a, b) for(typeof(b) i = (a); i < (b); ++i)
#define FOREACH(i, c) for(auto i = (c).begin(); i != (c).end(); ++i)

typedef long long ll;

struct Edge{
	int v, rev;
	int cap;
	Edge(int v_, int cap_, int rev_) : v(v_), rev(rev_), cap(cap_) {}
};

struct MaxFlow{
	vector<vector<Edge> > g;
	vector<int> level;
	queue<int> q;
	int flow, n;

	MaxFlow(int n_) : g(n_), level(n_), n(n_) {}

	void addEdge(int u, int v, int cap){
		if(u == v) return;
		Edge e(v, cap, int(g[v].size()));
		Edge r(u, 0, int(g[u].size()));
		g[u].push_back(e);
		g[v].push_back(r);
	}

	bool buildLevelGraph(int src, int sink){
		fill(ALL(level), -1);
		while(not q.empty()) q.pop();
		level[src] = 0;
		q.push(src);
		while(not q.empty()){
			int u = q.front();
			q.pop();
			FOREACH(e, g[u]){
				if(not e->cap or level[e->v] != -1) continue;
				level[e->v] = level[u] + 1;
				if(e->v == sink) return true;
				q.push(e->v);
			}
		}
		return false;
	}

	int blockingFlow(int u, int sink, int f){
		if(u == sink or not f) return f;
		int fu = f;
		FOREACH(e, g[u]){
			if(not e->cap or level[e->v] != level[u] + 1) continue;
			int mincap = blockingFlow(e->v, sink, min(fu, e->cap));
			if(mincap){
				g[e->v][e->rev].cap += mincap;
				e->cap -= mincap;
				fu -= mincap;
			}
		}
		if(f == fu) level[u] = -1;
		return f - fu;
	}

	int maxFlow(int src, int sink){
		flow = 0;
		while(buildLevelGraph(src, sink))
			flow += blockingFlow(src, sink, numeric_limits<int>::max());
		return flow;
	}
};
int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	int n, m;
	cin >> n >> m;

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

	int sol = numeric_limits<int>::max();
	for(int center = 0; center < n; center++){
		int cost = 0;
		for(int i = 0; i < n; i++)
			if(i != center)
				cost += abs(1 - mat[center][i]) + abs(1 - mat[i][center]);
			else
				cost += abs(1 - mat[i][i]);

		int newm = 0;
		MaxFlow gflow(n + n + 2);
		for(int u = 0; u < n; u++){
			if(u == center) continue;
			gflow.addEdge(n + n, u, 1);
			gflow.addEdge(u + n, n + n + 1, 1);
			for(const auto& v : gorig[u]){
				if(v == center) continue;
				gflow.addEdge(u, v + n, 1);
				newm++;
			}
		}
		int flow = gflow.maxFlow(n + n, n + n + 1);
		int add = n - 1 - flow;
		int remove = newm + add - (n - 1);
		cost += add + remove;
		sol = min(sol, cost);
	}

	cout << sol << endl;
}


#include <bits/extc++.h>
#include <iostream>

using namespace std;

//#define NDEBUG
#ifdef NDEBUG
#define DEBUG if (false)
#else
#define DEBUG if (true)
#endif
#define WRITE(x) DEBUG { cout << (x) << endl; }
#define WATCH(x) DEBUG { cout << #x << " = " << (x) << endl; }
#define ALL(x) (x).begin(), (x).end()
//#define FORN(i, a, b) for(typeof(b) i = (a); i < (b); ++i)
#define FOREACH(i, c) for(auto i = (c).begin(); i != (c).end(); ++i)

typedef long long ll;

struct Edge{
	int v, rev;
	int cap;
	Edge(int v_, int cap_, int rev_) : v(v_), rev(rev_), cap(cap_) {}
};

struct MaxFlow{
	vector<vector<Edge> > g;
	vector<int> level;
	queue<int> q;
	int flow, n;

	MaxFlow(int n_) : g(n_), level(n_), n(n_) {}

	void addEdge(int u, int v, int cap){
		if(u == v) return;
		Edge e(v, cap, int(g[v].size()));
		Edge r(u, 0, int(g[u].size()));
		g[u].push_back(e);
		g[v].push_back(r);
	}

	bool buildLevelGraph(int src, int sink){
		fill(ALL(level), -1);
		while(not q.empty()) q.pop();
		level[src] = 0;
		q.push(src);
		while(not q.empty()){
			int u = q.front();
			q.pop();
			FOREACH(e, g[u]){
				if(not e->cap or level[e->v] != -1) continue;
				level[e->v] = level[u] + 1;
				if(e->v == sink) return true;
				q.push(e->v);
			}
		}
		return false;
	}

	int blockingFlow(int u, int sink, int f){
		if(u == sink or not f) return f;
		int fu = f;
		FOREACH(e, g[u]){
			if(not e->cap or level[e->v] != level[u] + 1) continue;
			int mincap = blockingFlow(e->v, sink, min(fu, e->cap));
			if(mincap){
				g[e->v][e->rev].cap += mincap;
				e->cap -= mincap;
				fu -= mincap;
			}
		}
		if(f == fu) level[u] = -1;
		return f - fu;
	}

	int maxFlow(int src, int sink){
		flow = 0;
		while(buildLevelGraph(src, sink))
			flow += blockingFlow(src, sink, numeric_limits<int>::max());
		return flow;
	}
};
int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(0);

	int n, m;
	cin >> n >> m;

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

	int sol = numeric_limits<int>::max();
	for(int center = 0; center < n; center++){
		int cost = 0;
		for(int i = 0; i < n; i++)
			cost += (1 - mat[center][i]) + (1 - mat[i][center]);

		int newm = 0;
		MaxFlow gflow(n + n + 2);
		for(int u = 0; u < n; u++){
			if(u == center) continue;
			gflow.addEdge(n + n, u, 1);
			gflow.addEdge(u + n, n + n + 1, 1);
			for(const auto& v : gorig[u]){
				if(v == center) continue;
				gflow.addEdge(u, v + n, 1);
				newm++;
			}
		}
		int flow = gflow.maxFlow(n + n, n + n + 1);
		int add = n - 1 - flow;
		int remove = newm + add - (n - 1);
		cost += add + remove;
		sol = min(sol, cost);
	}

	cout << sol << endl;
}


#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;

namespace Dinic {
	const int N = 16384, M = N << 4;
	struct edge { int t, c; edge *op, *n; }
		ebf[M], *ec = ebf, *e[N], *er[N];
	int n, s, t, d[N];
	inline void add (int s, int t, int c)
	{
		*ec = (edge){t, c, ec + 1, er[s]}; er[s] = ec++;
		*ec = (edge){s, 0, ec - 1, er[t]}; er[t] = ec++;
	}
	inline void reset ()
	{
		memset(er, 0, sizeof(er[0]) * (n + 1));
		memset(d, 0, sizeof(d[0]) * (n + 1));
		n = 0; ec = ebf;
	}
	bool modlabel ()
	{
		static int que[M];
		int l(0), r(0), x, y;
		memcpy(e, er, sizeof(er[0]) * (n + 1));
		memset(d, 0xff, sizeof(d[0]) * (n + 1));
		d[que[++r] = s] = 0;
		while (l != r)
			for (edge *i = er[x = que[++l]]; i; i = i->n)
				if (i->c && d[y = i->t] < 0) d[que[++r] = y] = d[x] + 1;
		return d[t] >= 0;
	}
	int augument (int x, int c)
	{
		if (x == t) return c;
		int r(c), y, de; edge *i;
		for (i = e[x]; i; i = i->n)
			if (i->c && d[x] + 1 == d[y = i->t])
			{
				de = augument(y, min(r, i->c));
				i->c -= de, i->op->c += de, r -= de;
				if (!r) break;
			}
		e[x] = i;
		if (r) d[x] = -1; // CRUCIAL OPTIMIZATION
		return c - r;
	}
	int solve (int _n, int _s, int _t)
	{
		int res = 0, de; n = _n; s = _s; t = _t;
		while (modlabel()) while (de = augument(s, ~0U >> 1)) res += de;
		return res;
	}
}

const int N = 505, M = 1024;

int G[N][N], n, m;
vector<int> e[N];

int main ()
{
#ifdef LOCAL
	freopen("in", "r", stdin);
#endif
	scanf("%d%d", &n, &m);
	for (int i = 1, a, b; i <= m; ++i)
	{
		scanf("%d%d", &a, &b);
		G[a][b] = 1;
		e[a].push_back(b);
	}

	int res = ~0u >> 2;
	for (int i = 1; i <= n; ++i)
	{
		// i center
		int base = 0;
		for (int j = 1; j <= n; ++j)
			if (i != j) base += !G[i][j] + !G[j][i];
			else base += !G[i][j];

		if (base >= res)
			continue;

		int ec = 0;
		Dinic::reset();
		for (int x = 1; x <= n; ++x)
			if (x != i)
			{
				for (int y : e[x]) if (y != i)
				{
					++ec;
					Dinic::add(x, y + n, 1);
				}

				Dinic::add(n * 2 + 1, x, 1);
				Dinic::add(x + n, n * 2 + 2, 1);
			}
		int ret = Dinic::solve(n * 2 + 2, n * 2 + 1, n * 2 + 2);
		res = min(res, base + ec - (n - 1) + ((n - 1 - ret) * 2));
	}
	printf("%d\n", res);
}


#pragma comment(linker, "/STACK:64000000")
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <cstring>
#include <map>
#include <set>
#include <string>
#include <deque>
#include <algorithm>
#define _USE_MATH_DEFINES
#include <math.h>
using namespace std;
#define forn(i,n) for (int i=0;i<n;i++)
#define rforn(i,n) for (int i=n-1;i>=0;i--)
#define mp make_pair
#define __int64 long long
#define LL long long

bool kuhn(int p, vector <vector <int> > &gr, vector <bool> &fl, vector <int> &to)
{
	if (fl[p])
		return false;
	fl[p]=1;
	int t;
	forn(i,gr[p].size())
	{
		t=gr[p][i];
		if (to[t]==-1 || kuhn(to[t],gr,fl,to))
		{
			to[t]=p;
			return true;
		}
	}
}

int main()
{
	ios_base::sync_with_stdio(false);
	#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	#endif

	int n,m,a,b;
	cin>>n>>m;
	vector <vector <int> > gr(n);
	forn(i,m)
	{
		cin>>a>>b;
		a--;
		b--;
		gr[a].push_back(b);
	}
	int res=0,mres=-1;
	bool can;
	forn(t,n)
	{
		res=gr[t].size();
		forn(i,n)
		{
			if (i==t)
				continue;
			can=false;
			forn(j,gr[i].size())
				if (gr[i][j]==t)
					can=true;
			if (can)
				res++;
		}
		vector <vector <int> > gr2(2*n);
		vector <int> to(2*n,-1);
		vector <bool> fl(2*n,0);
		forn(i,n)
		{
			if (i==t)
				continue;
			forn(j,gr[i].size())
			{
				gr2[i].push_back(n+gr[i][j]);
			}
		}

		forn(i,n)
		{
			fl.assign(2*n,0);
			if (kuhn(i,gr2,fl,to))
			{
				res++;
			}
		}

		res=m-res+((n-1)+2*(n-1)+1)-res;
		if (mres==-1 || mres>res)
			mres=res;
	}
	cout<<mres;
}


#pragma comment(linker, "/STACK:64000000")
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <cstring>
#include <map>
#include <set>
#include <string>
#include <deque>
#include <algorithm>
#define _USE_MATH_DEFINES
#include <math.h>
using namespace std;
#define forn(i,n) for (int i=0;i<n;i++)
#define rforn(i,n) for (int i=n-1;i>=0;i--)
#define mp make_pair
#define __int64 long long
#define LL long long

bool kuhn(int p, vector <vector <int> > &gr, vector <bool> &fl, vector <int> &to)
{
	if (fl[p])
		return false;
	fl[p]=1;
	int t;
	forn(i,gr[p].size())
	{
		t=gr[p][i];
		if (to[t]==-1 || kuhn(to[t],gr,fl,to))
		{
			to[t]=p;
			return true;
		}
	}
}

int main()
{
	ios_base::sync_with_stdio(false);
	#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	#endif

	int n,m,a,b;
	cin>>n>>m;
	vector <vector <int> > gr(n);
	forn(i,m)
	{
		cin>>a>>b;
		a--;
		b--;
		gr[a].push_back(b);
	}
	int res=0,mres=-1;
	bool can;
	forn(t,n)
	{
		res=gr[t].size();
		forn(i,n)
		{
			if (i==t)
				continue;
			can=false;
			forn(j,gr[i].size())
				if (gr[i][j]==t)
					can=true;
			if (can)
				res++;
		}
		vector <vector <int> > gr2(2*n);
		vector <int> to(2*n,-1);
		vector <bool> fl(2*n,0);
		forn(i,n)
		{
			if (i==t)
				continue;
			forn(j,gr[i].size())
			{
				if (gr[i][j]==t)
					continue;
				gr2[i].push_back(n+gr[i][j]);
			}
		}

		forn(i,n)
		{
			fl.assign(2*n,0);
			if (kuhn(i,gr2,fl,to))
			{
				res++;
			}
		}

		res=m-res+((n-1)+2*(n-1)+1)-res;
		if (mres==-1 || mres>res)
			mres=res;
	}
	cout<<mres;
}


#pragma comment(linker, "/STACK:64000000")
#include <stdlib.h>
#include <fstream>
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#include <cstring>
#include <map>
#include <set>
#include <string>
#include <deque>
#include <algorithm>
#define _USE_MATH_DEFINES
#include <math.h>
using namespace std;
#define forn(i,n) for (int i=0;i<n;i++)
#define rforn(i,n) for (int i=n-1;i>=0;i--)
#define mp make_pair
#define __int64 long long
#define LL long long

bool kuhn(int p, vector <vector <int> > &gr, vector <bool> &fl, vector <int> &to)
{
	if (fl[p])
		return false;
	fl[p]=1;
	int t;
	forn(i,gr[p].size())
	{
		t=gr[p][i];
		if (to[t]==-1 || kuhn(to[t],gr,fl,to))
		{
			to[t]=p;
			return true;
		}
	}
	return false;
}

int main()
{
	ios_base::sync_with_stdio(false);
	#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
	#endif

	int n,m,a,b;
	cin>>n>>m;
	vector <vector <int> > gr(n);
	forn(i,m)
	{
		cin>>a>>b;
		a--;
		b--;
		gr[a].push_back(b);
	}
	int res=0,mres=-1;
	bool can;
	forn(t,n)
	{
		res=gr[t].size();
		forn(i,n)
		{
			if (i==t)
				continue;
			can=false;
			forn(j,gr[i].size())
				if (gr[i][j]==t)
					can=true;
			if (can)
				res++;
		}
		vector <vector <int> > gr2(2*n);
		vector <int> to(2*n,-1);
		vector <bool> fl(2*n,0);
		forn(i,n)
		{
			if (i==t)
				continue;
			forn(j,gr[i].size())
			{
				if (gr[i][j]==t)
					continue;
				gr2[i].push_back(n+gr[i][j]);
			}
		}

		forn(i,n)
		{
			fl.assign(2*n,0);
			if (kuhn(i,gr2,fl,to))
			{
				res++;
			}
		}

		res=m-res+((n-1)+2*(n-1)+1)-res;
		if (mres==-1 || mres>res)
			mres=res;
	}
	cout<<mres;
}


#include <climits>
#include <set>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int n,m;
int mat[512][512];
int indeg[512], outdeg[512];

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 0; i < m; i++) {
		int a,b;
		scanf("%d%d",&a,&b);
		a--,b--;
		indeg[b]++, outdeg[a]++;
		mat[a][b] = 1;
}
	int ans = INT_MAX;
	for(int i = 0; i < n; i++) { // consider i as center
		int cur = 0;
		int diff1 = 0;
		int diff2 = 0;
		for(int j = 0; j < n; j++) {
			if (i == j) {
				if (mat[i][i] == 0) {
					cur++;
				}
				continue;
			}
			bool hasCenterIn = mat[j][i];
			bool hasCenterOut = mat[i][j];
			if (!hasCenterIn) cur++;
			if (!hasCenterOut) cur++;
			int myOutDeg = outdeg[j] - (hasCenterIn?1:0);
			int myInDeg = indeg[j] - (hasCenterOut?1:0);
			diff1 += std::abs(1-myOutDeg);
			diff2 += std::abs(1-myInDeg);
		}
		ans = min(ans, cur + max(diff1,diff2));
	}
	printf("%d\n",ans);
	return 0;
}


#include <climits>
#include <memory.h>
#include <set>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int n,m;
int mat[512][512];
int indeg[512], outdeg[512];
vector<int> graph[512];
// in: n, m, graph
// out: match
namespace HopcroftKarp
{
	const int MAX_N = 503, MAX_M = 503;
	int n, m;
	vector<int> graph[MAX_N];
	int match[MAX_N];

	int matched[MAX_M], depth[MAX_N], q[MAX_N];
	int v[MAX_N], vcnt;
	bool BFS(){
		int t = 0;
		for(int i = 0; i < n; i++)
			if (match[i] == -1) depth[i] = 0, q[t++] = i;
			else depth[i] = -1;
			for(int h = 0; h < t; h++) {
				int cur = q[h];
				int curDepth = depth[cur];
				for(int i = 0; i < graph[cur].size(); i++) {
					int adj = graph[cur][i];
					if (matched[adj] == -1)
						return true;
					int next = matched[adj];
					if (depth[next] != -1) continue;
					depth[next] = curDepth + 1, q[t++] = next;
				}
			}
			return false;
	}

	bool DFS(int nod) {
		v[nod] = vcnt;
		for(int i = 0; i < graph[nod].size(); i++) {
			int adj = graph[nod][i];
			int next = matched[adj];
			if (next >= 0 && (v[next] == vcnt || depth[next] != depth[nod] + 1))
				continue;
			if (next == -1 || DFS(next)) {
				match[nod] = adj;
				matched[adj] = nod;
				return true;
			}
		}
		return false;
	}

	int Match()
	{
		memset(match, -1, sizeof(match));
		memset(matched, -1, sizeof(matched));
		int ans = 0;
		while(BFS()) {
			++vcnt;
			for(int i = 0; i < n; i++) if (depth[i] == 0 && DFS(i)) ans++;
		}
		return ans;
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 0; i < m; i++) {
		int a,b;
		scanf("%d%d",&a,&b);
		a--,b--;
		indeg[b]++, outdeg[a]++;
		mat[a][b] = 1;
		graph[a].push_back(b);
	}
	int ans = INT_MAX;
	for(int i = 0; i < n; i++) { // consider i as center
		int cur = 0;
		HopcroftKarp::n = n-1;
		HopcroftKarp::m = n-1;
		for(int j = 0; j < n-1; j++)HopcroftKarp::graph[j].clear();
		int totalEdges = 0;
		for(int j = 0; j < n; j++) {
			if (i == j) {
				if (mat[i][i] == 0) {
					cur++;
				}
				continue;
			}
			bool hasCenterIn = mat[j][i];
			bool hasCenterOut = mat[i][j];
			if (!hasCenterIn) cur++;
			if (!hasCenterOut) cur++;
			for(auto next : graph[j]) {
				if (next == i) continue;
				HopcroftKarp::graph[j-(j>i)].push_back(next-(next>i));
				totalEdges++;
			}
		}
		int left = HopcroftKarp::Match();
		cur += (totalEdges - left) + (n-1 - left);
		ans = min(ans, cur);
	}
	printf("%d\n",ans);
	return 0;
}


#include <climits>
#include <set>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int n,m;
int mat[512][512];
int indeg[512], outdeg[512];
vector<int> graph[512];
// in: n, m, graph
// out: match
namespace HopcroftKarp
{
	const int MAX_N = 503, MAX_M = 503;
	int n, m;
	vector<int> graph[MAX_N];
	int match[MAX_N];

	int matched[MAX_M], depth[MAX_N], q[MAX_N];
	int v[MAX_N], vcnt;
	bool BFS(){
		int t = 0;
		for(int i = 0; i < n; i++)
			if (match[i] == -1) depth[i] = 0, q[t++] = i;
			else depth[i] = -1;
			for(int h = 0; h < t; h++) {
				int cur = q[h];
				int curDepth = depth[cur];
				for(int i = 0; i < graph[cur].size(); i++) {
					int adj = graph[cur][i];
					if (matched[adj] == -1)
						return true;
					int next = matched[adj];
					if (depth[next] != -1) continue;
					depth[next] = curDepth + 1, q[t++] = next;
				}
			}
			return false;
	}

	bool DFS(int nod) {
		v[nod] = vcnt;
		for(int i = 0; i < graph[nod].size(); i++) {
			int adj = graph[nod][i];
			int next = matched[adj];
			if (next >= 0 && (v[next] == vcnt || depth[next] != depth[nod] + 1))
				continue;
			if (next == -1 || DFS(next)) {
				match[nod] = adj;
				matched[adj] = nod;
				return true;
			}
		}
		return false;
	}

	int Match()
	{
		memset(match, -1, sizeof(match));
		memset(matched, -1, sizeof(matched));
		int ans = 0;
		while(BFS()) {
			++vcnt;
			for(int i = 0; i < n; i++) if (depth[i] == 0 && DFS(i)) ans++;
		}
		return ans;
	}
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 0; i < m; i++) {
		int a,b;
		scanf("%d%d",&a,&b);
		a--,b--;
		indeg[b]++, outdeg[a]++;
		mat[a][b] = 1;
		graph[a].push_back(b);
	}
	int ans = INT_MAX;
	for(int i = 0; i < n; i++) { // consider i as center
		int cur = 0;
		HopcroftKarp::n = n-1;
		HopcroftKarp::m = n-1;
		for(int j = 0; j < n-1; j++)HopcroftKarp::graph[j].clear();
		int totalEdges = 0;
		for(int j = 0; j < n; j++) {
			if (i == j) {
				if (mat[i][i] == 0) {
					cur++;
				}
				continue;
			}
			bool hasCenterIn = mat[j][i];
			bool hasCenterOut = mat[i][j];
			if (!hasCenterIn) cur++;
			if (!hasCenterOut) cur++;
			for(auto next : graph[j]) {
				if (next == i) continue;
				HopcroftKarp::graph[j-(j>i)].push_back(next-(next>i));
				totalEdges++;
			}
		}
		int left = HopcroftKarp::Match();
		cur += (totalEdges - left) + (n-1 - left);
		ans = min(ans, cur);
	}
	printf("%d\n",ans);
	return 0;
}


#include <climits>
#include <set>
#include <cstdio>
#include <vector>
#include <cmath>
#include <algorithm>

using namespace std;

int n,m;
set<int> graph[512];
int indeg[512], outdeg[512];

int main(){
	scanf("%d%d",&n,&m);
	for(int i = 0; i < m; i++) {
		int a,b;
		scanf("%d%d",&a,&b);
		a--,b--;
		indeg[b]++, outdeg[a]++;
		graph[a].insert(b);
	}
	int ans = INT_MAX;
	for(int i = 0; i < n; i++) { // consider i as center
		int cur = 0;
		int diff = 0;
		for(int j = 0; j < n; j++) {
			if (i == j) {
				if (graph[i].count(i) == 0) {
					cur++;
				}
				continue;
			}
			bool hasCenterIn = graph[j].count(i) > 0;
			bool hasCenterOut = graph[i].count(j) > 0;
			if (!hasCenterIn) cur++;
			if (!hasCenterOut) cur++;
			if (outdeg[j] != (hasCenterIn?1:0) + 1) {
				diff += std::abs(outdeg[j] - (hasCenterIn?1:0) - 1);
			}
			if (indeg[j] != (hasCenterOut?1:0) + 1) {
				diff += std::abs(indeg[j] - (hasCenterOut?1:0) - 1);
			}
		}
		ans = min(ans, cur + diff/2);
	}
	printf("%d\n",ans);
	return 0;
}


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	for(int c =0; c < N; c++) {
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}
		if(N != 500) {

		while(true) {
			vector<int> ako(2*N,-1);
			queue<int> q;
			ako[0] =0;
			q.push(0);
			while(!q.empty()) {
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					q.push(*it);}
				q.pop();}
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}
			}
		}
		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =1;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =1;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =1;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	srand(M);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		srand(rand()%(a*b));
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0, c =0;
	set<int> s;
	for(int i =0; i < N; i++) s.insert(i);
	srand(42);
	for(int k =0; k < min(300,N); k++) {
		c =rand()%N;
		while(s.find(c) == s.end()) c =rand()%N;
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;
		if(M-akt+(N-2-akt) >= ans) continue;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			while(!q.empty()) {
				g +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));
		s.erase(c);
		if(N > 400 && g > 200000000) {cout << k << "\n"; break;}}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	for(int c =0; c < N; c++) {
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			int t =0;
			while(!q.empty()) {
				t++;
				if(ako[2*N-1] != -1 || (N == 500 && t > N+N/10)) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	srand(M*N);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0, c =0;
	if(N == 499) srand(43+M%999);
	vector<int> s(N);
	for(int i =0; i < N; i++) s[i] =i;
	for(int k =0; k < min(310,N); k++) {
		c =s[rand()%s.size()];
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;
		if(M-akt+(N-2-akt) >= ans) {
			ALL_THE(s,it) if(*it == c) {
				s.erase(it);
				break;}
			continue;}

		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));
				if(F[0][i+1-int(i > c)] && F[N+*it-int(*it > c)][2*N-1]) {
					F[0][i+1-int(i > c)] =F[N+*it-int(*it > c)][2*N-1] =0;
					F[i+1-int(i > c)][0] =F[2*N-1][N+*it-int(*it > c)] =1;
					akt++;}
				}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			while(!q.empty()) {
				g +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));
		ALL_THE(s,it) if(*it == c) {
			s.erase(it);
			break;}
		if(N > 400 && g > 200000000) break;}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	srand(M);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		srand(rand()%(a*b));
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0, c =rand()%N;
	set<int> s;
	for(int i =0; i < N; i++) s.insert(i);
	for(int k =0; k < N; k++) {
		c =rand()%N;
		while(s.find(c) == s.end()) c =rand()%N;
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			while(!q.empty()) {
				g +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));
		s.erase(c);
		if(N > 400 && g > 200000000) break;}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	srand(M);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		srand(rand()%(a*b));
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0, c =0;
	set<int> s;
	for(int i =0; i < N; i++) s.insert(i);
	for(int i =0; i < N; i++) swap(s[i],s[i+rand()%(N-i)]);
	for(int k =0; k < min(300,N); k++) {
		c =rand()%N;
		while(s.find(c) == s.end()) c =rand()%N;
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;
		if(M-akt+(N-2-akt) >= ans) continue;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			while(!q.empty()) {
				g +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));
		s.erase(c);
		if(N > 400 && g > 200000000) {if(N == 499 && M == 999) cout << k << "\n"; break;}}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	srand(time(0));
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0, c =0;
	set<int> s;
	for(int i =0; i < N; i++) s.insert(i);
	for(int k =0; k < min(N,300); k++) {
		c =rand()%N;
		while(s.find(c) == s.end()) c =rand()%N;
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			int t =0;
			while(!q.empty()) {
				t +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			if(t > M+2*N && N > 300) g++;
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));
		s.erase(c);
		if(N > 300 && g > N/3) break;}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0;
	for(int c =0; c < N; c++) {
		if(N > 300 && g > N/3) break;
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			int t =0;
			while(!q.empty()) {
				t +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			if(t > M+2*N && N > 300) g++;
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	vector< vector<int> > G0(N);
	srand(M);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		srand(rand()%(a*b));
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0, c =0;
	set<int> s;
	for(int i =0; i < N; i++) s.insert(i);
	srand(42);
	for(int k =0; k < min(300,N); k++) {
		c =rand()%N;
		while(s.find(c) == s.end()) c =rand()%N;
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;
		if(M-akt+(N-2-akt) >= ans) continue;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			while(!q.empty()) {
				g +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));
		s.erase(c);
		if(N > 400 && g > 200000000) {if(N == 499 && M == 999) cout << k << "\n"; break;}}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing


// iostream is too mainstream
#include <cstdio>
// bitch please
#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <iomanip>
#define dibs reserve
#define OVER9000 1234567890
#define patkan 9
#define tisic 47
#define soclose 1e-9
#define pi 3.1415926535898
#define ALL_THE(CAKE,LIE) for(auto LIE =CAKE.begin(); LIE != CAKE.end(); LIE++)
#define chocolate win
#define ff first
#define ss second
#define abs(x) ((x < 0)?-(x):(x))
#define uint unsigned int
// mylittlepony
using namespace std;

int main() {
	cin.sync_with_stdio(0);
	int N,M, ans =OVER9000;
	cin >> N >> M;
	srand(M);
	vector< vector<int> > G0(N);
	for(int i =0; i < M; i++) {
		int a,b;
		cin >> a >> b;
		G0[--a].push_back(--b);}

	vector< vector<int> > F(2*N,vector<int>(2*N,0));
	vector< vector<int> > G(2*N);
	int g =0, c =rand()%N;
	set<int> s;
	for(int i =0; i < N; i++) s.insert(i);
	for(int k =0; k < min(N,300); k++) {
		c =rand()%N;
		while(s.find(c) == s.end()) c =rand()%N;
		int akt =G0[c].size();
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it == c) akt++;

		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =1;
				G[i+1-int(i > c)].push_back(N+*it-int(*it > c));
				G[N+*it-int(*it > c)].push_back(i+1-int(i > c));}
		for(int i =0; i < N; i++) if(i != c) {
			F[0][i+1-int(i > c)] =1;
			G[0].push_back(i+1-int(i > c));
			G[i+1-int(i > c)].push_back(0);}
		for(int i =0; i < N; i++) if(i != c) {
			F[N+i-int(i > c)][2*N-1] =1;
			G[2*N-1].push_back(N+i-int(i > c));
			G[N+i-int(i > c)].push_back(2*N-1);}

		vector<int> ako(2*N,-1),inQ;
		ako[0] =0;
		queue<int> q;
		while(true) {
			q.push(0);
			while(!q.empty()) {
				g +=G[q.front()].size();
				if(ako[2*N-1] != -1) break;
				ALL_THE(G[q.front()],it) if(ako[*it] == -1 && F[q.front()][*it] > 0) {
					ako[*it] =q.front();
					inQ.push_back(*it);
					q.push(*it);}
				q.pop();}
			while(!q.empty()) q.pop();
			if(ako[2*N-1] == -1) break;

			akt++;
			int a =2*N-1;
			while(a > 0) {
				F[ako[a]][a]--;
				F[a][ako[a]]++;
				a =ako[a];}

			ALL_THE(inQ,it) ako[*it] =-1;
			inQ.clear();}

		for(int i =0; i < 2*N; i++) {
			G[i].clear();}
		for(int i =0; i < N; i++) if(i != c)
			ALL_THE(G0[i],it) if(*it != c) {
				F[i+1-int(i > c)][N+*it-int(*it > c)] =0;
				F[N+*it-int(*it > c)][i+1-int(i > c)] =0;}
		for(int i =0; i < N; i++) if(i != c)
			F[0][i+1-int(i > c)] =F[i+1-int(i > c)][0] =0;
		for(int i =0; i < N; i++) if(i != c)
			F[N+i-int(i > c)][2*N-1] =F[2*N-1][N+i-int(i > c)] =0;

		ans =min(ans,M-akt+(N-1+1+2*(N-1)-akt));
		s.erase(c);
		if(N > 400 && g > 100000000) break;}

	cout << ans << "\n";
	return 0;}

// look at my code
// my code is amazing