#include <bits/stdc++.h>
using namespace std;
const double PI = acos(-1.0);
long double fixAngle(long double A) { return A > 1 ? 1 : (A < -1 ? -1 : A); }
double dcmp(double a, double b) {
  return fabs(a - b) < 1e-7 ? 0 : a > b ? 1 : -1;
}
bool ison(long long m, long long i) { return (m & (1 << i)) != 0; }
long long mypow(long long n, long long m) {
  if (!m) return 1;
  return (m % 2 == 0) ? mypow(n, m / 2) * mypow(n, m / 2) : n * mypow(n, m - 1);
}
const int INF = 1000000000;
;
struct Edge {
  int from, to, cap, flow, index;
  Edge(int from, int to, int cap, int flow, int index)
      : from(from), to(to), cap(cap), flow(flow), index(index) {}
};
struct Dinic {
  int N;
  vector<vector<Edge> > G;
  vector<Edge *> dad;
  vector<int> Q;
  Dinic(int N) : N(N), G(N), dad(N), Q(N) {}
  void AddEdge(int from, int to, int cap) {
    G[from].push_back(Edge(from, to, cap, 0, G[to].size()));
    if (from == to) G[from].back().index++;
    G[to].push_back(Edge(to, from, 0, 0, G[from].size() - 1));
  }
  long long BlockingFlow(int s, int t) {
    fill(dad.begin(), dad.end(), (Edge *)NULL);
    dad[s] = &G[0][0] - 1;
    int head = 0, tail = 0;
    Q[tail++] = s;
    while (head < tail) {
      int x = Q[head++];
      for (int i = 0; i < G[x].size(); i++) {
        Edge &e = G[x][i];
        if (!dad[e.to] && e.cap - e.flow > 0) {
          dad[e.to] = &G[x][i];
          Q[tail++] = e.to;
        }
      }
    }
    if (!dad[t]) return 0;
    long long totflow = 0;
    for (int i = 0; i < G[t].size(); i++) {
      Edge *start = &G[G[t][i].to][G[t][i].index];
      int amt = INF;
      for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
        if (!e) {
          amt = 0;
          break;
        }
        amt = min(amt, e->cap - e->flow);
      }
      if (amt == 0) continue;
      for (Edge *e = start; amt && e != dad[s]; e = dad[e->from]) {
        e->flow += amt;
        G[e->to][e->index].flow -= amt;
      }
      totflow += amt;
    }
    return totflow;
  }
  long long GetMaxFlow(int s, int t) {
    long long totflow = 0;
    while (long long flow = BlockingFlow(s, t)) totflow += flow;
    return totflow;
  }
};
int n, m;
vector<pair<long long, long long> > data;
void make_graph(Dinic &f, int k) {
  int s = n + m;
  int t = n + m + 1;
  for (int i = 0; i < m; i++) {
    f.AddEdge(s, i, 1);
    f.AddEdge(i, data[i].second + m, 1);
    f.AddEdge(i, data[i].first + m, 1);
  }
  for (int i = 0; i < n; i++) {
    f.AddEdge(m + i, t, k);
  }
}
bool check_graph(int k) {
  Dinic f(n + m + 2);
  make_graph(f, k);
  return f.GetMaxFlow(n + m, n + m + 1) == m;
}
int solve() {
  int low = 0;
  int high = n;
  while (high - low > 1) {
    int mid = high + low;
    mid /= 2;
    if (check_graph(mid)) {
      high = mid;
    } else {
      low = mid + 1;
    }
  }
  if (check_graph(low)) return low;
  return high;
}
int main() {
  cin >> n >> m;
  data.resize(m);
  for (long long i = 0; i < m; i++) {
    cin >> data[i].first >> data[i].second;
    data[i].first--;
    data[i].second--;
  }
  int ans = solve();
  Dinic f(n + m + 2);
  make_graph(f, ans);
  f.GetMaxFlow(n + m, n + m + 1);
  cout << ans << endl;
  for (auto G : f.G) {
    for (auto e : G) {
      if (e.from >= 0 && e.from < m) {
        if (e.to >= m && e.to < m + n) {
          if (e.flow >= 1) {
            int from;
            if (data[e.from].first + 1 != e.to - m + 1)
              from = data[e.from].first;
            else
              from = data[e.from].second;
            cout << e.to - m + 1 << " " << from + 1 << endl;
            ;
          }
        }
      }
    }
  }
}
