#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:56777216")
const int INF = 1000 * 1000 * 1000;
const long long LINF = INF * 1ll * INF;
const double EPS = 1e-9;
void Out(const vector<int>& v) {
  for (auto x : v) {
    cout << x << " ";
  }
  cout << endl;
}
template <typename T>
void fill(vector<T>& v, T val) {
  std::fill(v.begin(), v.end(), val);
}
std::vector<std::string>& split(const std::string& s, char delim,
                                std::vector<std::string>& elems) {
  std::stringstream ss(s);
  std::string item;
  while (std::getline(ss, item, delim)) {
    elems.push_back(item);
  }
  return elems;
}
std::vector<std::string> split(const std::string& s, char delim) {
  std::vector<std::string> elems;
  split(s, delim, elems);
  return elems;
}
template <typename T>
inline T abs(T a) {
  return a < 0 ? -a : a;
}
template <typename T>
inline T sqr(T x) {
  return x * x;
}
vector<pair<int, int> > g;
int n, m;
bool dfs(int from, const vector<vector<int> >& g, vector<int>& visited,
         vector<int>& pair) {
  if (visited[from]) return false;
  visited[from] = true;
  for (int to : g[from]) {
    if (pair[to] == -1 || dfs(pair[to], g, visited, pair)) {
      pair[from] = to;
      pair[to] = from;
      return true;
    }
  }
  return false;
}
vector<int> FindMaximumMatch(const vector<vector<int> >& g) {
  vector<int> visited(((int)(g).size()), false);
  vector<int> pair(((int)(g).size()), -1);
  vector<int> ind(((int)(g).size()));
  iota(ind.begin(), ind.end(), 0);
  random_shuffle(ind.begin(), ind.end());
  for (auto from : ind) {
    if (pair[from] == -1) {
      for (auto to : g[from]) {
        if (pair[to] == -1) {
          pair[to] = from;
          pair[from] = to;
          break;
        }
      }
    }
  }
  for (int i = 0; i < ((int)(g).size()); ++i) {
    if (pair[i] == -1) {
      if (dfs(i, g, visited, pair)) {
        fill(visited, 0);
      }
    }
  }
  return pair;
}
int GetNode(int old, int removed) {
  if (old < removed) return old;
  return old - 1;
}
vector<vector<int> > BuildFilteredBipartite(const vector<pair<int, int> >& g,
                                            int removed, int nodesCount) {
  nodesCount--;
  vector<vector<int> > bipartite(nodesCount * 2);
  for (const auto& e : g) {
    if (e.first == removed || e.second == removed) continue;
    int from = GetNode(e.first, removed);
    int to = GetNode(e.second, removed);
    bipartite[from].push_back(nodesCount + to);
  }
  return bipartite;
}
int answer = INF;
void Solve() {
  answer = INF;
  for (int i = 0; i < n; ++i) {
    int countEdges = ((int)(g).size());
    int countCorrect = 0;
    for (auto edge : g) {
      if (edge.first == i || edge.second == i) {
        countCorrect++;
      }
    }
    int penalty = 2 * n - 1 - countCorrect;
    vector<vector<int> > gFiltered = BuildFilteredBipartite(g, i, n);
    vector<int> matching = FindMaximumMatch(gFiltered);
    int countNotSet = 0;
    for (auto x : matching) {
      if (x == -1) countNotSet++;
    }
    countNotSet /= 2;
    int countSet = ((int)(matching).size()) / 2 - countNotSet;
    int edgesRemoved = countEdges - countCorrect - countSet;
    penalty += countNotSet + edgesRemoved;
    answer = min(answer, penalty);
  }
}
bool Input() {
  if (!(cin >> n >> m)) {
    return false;
  }
  g.clear();
  for (int i = 0; i < m; ++i) {
    int from, to;
    cin >> from >> to;
    from--;
    to--;
    g.push_back({from, to});
  }
  return true;
}
void Output() { cout << answer << endl; }
void Stress() {
  srand(123);
  exit(123);
  cerr << "passed" << endl;
}
int main() {
  ios_base::sync_with_stdio(0);
  while (Input()) {
    Solve();
    Output();
  }
  return 0;
}
