#include <bits/stdc++.h>
const int N = 100005;
using namespace std;
struct edge {
  int fr, to;
  edge(int f, int t) {
    fr = f;
    to = t;
  }
};
bool operator<(edge x1, edge x2) {
  if (x1.to == x2.to) {
    return x1.fr < x2.fr;
  } else {
    return x1.to < x2.to;
  }
}
int n, m;
vector<edge> E;
int f[N];
int ct[N];
int find(int x) {
  if (x == f[x]) {
    return x;
  } else {
    f[x] = find(f[x]);
    return f[x];
  }
}
set<int> s;
void unite(int i, int j) {
  int ri = find(i);
  int rj = find(j);
  ct[ri] += ct[rj];
  f[rj] = ri;
  s.erase(rj);
}
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) {
    f[i] = i;
    ct[i] = 1;
  }
  int t1, t2, x1, x2;
  for (int i = 0; i < m; i++) {
    scanf("%d%d", &t1, &t2);
    x1 = t1 < t2 ? t1 : t2;
    x2 = t1 > t2 ? t1 : t2;
    E.push_back(edge(x1, x2));
  }
  sort(E.begin(), E.end());
  int len = E.size();
  int j = 0;
  for (int i = 1; i <= n; i++) {
    map<int, int> M;
    s.insert(i);
    for (; j < len && E[j].to == i; j++) {
      int rt = find(E[j].fr);
      if (M.find(rt) == M.end()) {
        M[rt] = 1;
      } else {
        M[rt]++;
      }
    }
    set<int>::iterator iter;
    for (iter = s.begin(); iter != s.end(); iter++) {
      int rt = find(*iter);
      if (rt == i) {
        continue;
      }
      if (M.find(rt) == M.end() || M[rt] < ct[rt]) {
        unite(*iter, i);
      }
    }
  }
  printf("%d\n", s.size() - 1);
  return 0;
}
