#include <bits/stdc++.h>
using namespace std;
template <typename flow_t = long long>
struct push_relabel {
  struct edge {
    int to;
    int idx_of_reverse_edge;
    flow_t flow_val, capacity;
  };
  int n, s, t;
  vector<vector<edge>> adjList;
  vector<flow_t> excess;
  vector<int> height;
  vector<vector<int>> heightList;
  vector<edge *> curr;
  vector<int> heightCount;
  push_relabel(int n)
      : n(n),
        adjList(n),
        excess(n, 0),
        height(n, 0),
        heightList(2 * n),
        curr(n),
        heightCount(2 * n, 0) {}
  void add_edge(int u, int v, flow_t cap, flow_t rcap = 0) {
    if (u == v) return;
    adjList[u].push_back({v, (int)adjList[v].size(), 0, cap});
    adjList[v].push_back({u, (int)adjList[u].size() - 1, 0, rcap});
  }
  void add_flow(edge &e, flow_t f) {
    edge &reverse_edge = adjList[e.to][e.idx_of_reverse_edge];
    if (!excess[e.to] && f && e.to != t)
      heightList[height[e.to]].push_back(e.to);
    e.flow_val += f;
    e.capacity -= f;
    excess[e.to] += f;
    reverse_edge.flow_val -= f;
    reverse_edge.capacity += f;
    excess[reverse_edge.to] -= f;
  }
  int discharge(int v) {
    while (excess[v] > 0) {
      if (curr[v] == adjList[v].data() + adjList[v].size()) {
        int old_height = height[v];
        height[v] = 2 * n - 1;
        for (auto &e : adjList[v]) {
          if (e.capacity && height[v] > height[e.to]) {
            height[v] = height[e.to];
            curr[v] = &e;
          }
        }
        height[v]++;
        heightCount[height[v]]++;
        if (!--heightCount[old_height] && old_height < n) {
          for (int i = 0; i < n; i++) {
            if (height[i] > old_height && height[i] < n) {
              heightCount[height[i]]--;
              height[i] = n;
            }
          }
        }
      } else if (curr[v]->capacity && height[v] > height[curr[v]->to])
        add_flow(*curr[v], min(excess[v], curr[v]->capacity));
      else
        curr[v]++;
    }
    return height[v];
  }
  flow_t max_flow(int s, int t) {
    this->s = s;
    this->t = t;
    height[s] = n;
    heightCount[0] = n - 1;
    for (auto &e : adjList[s])
      if (e.capacity) add_flow(e, e.capacity);
    for (int i = 0; i < n; i++) curr[i] = adjList[i].data();
    if (heightList[0].empty()) return 0;
    int hi = 0;
    while (hi >= 0) {
      auto v = heightList[hi].back();
      heightList[hi].pop_back();
      hi = discharge(v);
      while (hi >= 0 && heightList[hi].empty()) hi--;
    }
    return excess[t];
  }
};
using ll = long long;
int binsearch(int l, int r, const function<bool(ll)> &check) {
  ll low = l;
  ll high = r + 1;
  ll mid;
  while (low < high) {
    mid = (low + high) / 2;
    bool temp = check(mid);
    if (temp)
      high = mid;
    else
      low = mid + 1;
  }
  return high;
}
void solve() {
  int n, m;
  cin >> n >> m;
  vector<pair<int, int>> edges(m);
  for (int i = 0; i < m; i++) cin >> edges[i].first >> edges[i].second;
  push_relabel<int> f(0);
  auto lambda = [&edges, n, m, &f](ll val) -> bool {
    f = push_relabel<int>(n + m + 2);
    for (int i = 1; i <= m; i++) f.add_edge(0, i, 1, 0);
    for (int i = 1; i <= m; i++) {
      f.add_edge(i, m + edges[i - 1].first, 1, 0);
      f.add_edge(i, m + edges[i - 1].second, 1, 0);
    }
    for (int i = m + 1; i <= m + n; i++) f.add_edge(i, m + n + 1, val, 0);
    return f.max_flow(0, m + n + 1) >= m;
  };
  int t = binsearch(0, n, lambda);
  cout << t << "\n";
  lambda(t);
  for (int i = 1; i <= m; i++) {
    for (auto e : f.adjList[i]) {
      if (e.flow_val == 1) {
        int u = edges[i - 1].first;
        int other = edges[i - 1].second;
        if (other == e.to - m) swap(u, other);
        cout << e.to - m << " " << other << "\n";
      }
    }
  }
}
int main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  solve();
}
