#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast,no-stack-protector")
#pragma GCC target( \
    "sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("fast-math")
#pragma GCC optimize("section-anchors")
#pragma GCC optimize("profile-values,profile-reorder-functions,tracer")
#pragma GCC optimize("vpt")
#pragma GCC optimize("rename-registers")
#pragma GCC optimize("move-loop-invariants")
#pragma GCC optimize("unswitch-loops")
#pragma GCC optimize("function-sections")
#pragma GCC optimize("data-sections")
#pragma GCC optimize("branch-target-load-optimize")
#pragma GCC optimize("branch-target-load-optimize2")
#pragma GCC optimize("btr-bb-exclusive")
const long long MOD = 1e9 + 7;
const long double PI = atan2(0, -1);
const long long inf = 1e9 + 123;
const long long infl = 2e18;
const long double eps = 1e-8;
long long gcd(long long a, long long b) { return a ? gcd(b % a, a) : b; }
const long long N = 2e5 + 100;
set<long long> g[N];
vector<long long> deg(N);
long long n, m;
vector<char> used(N);
set<long long> cur;
inline void dfs(long long v) {
  vector<long long> tmp;
  for (auto i : cur) {
    if (!g[v].count(i)) tmp.push_back(i);
  }
  for (auto i : tmp) cur.erase(i);
  for (auto i : tmp) dfs(i);
}
signed main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  cin >> n >> m;
  for (long long i = 0; i < m; i++) {
    long long a, b;
    cin >> a >> b;
    a--;
    b--;
    g[a].insert(b);
    g[b].insert(a);
    deg[a]++;
    deg[b]++;
  }
  for (long long i = 0; i < n; i++) cur.insert(i);
  vector<long long> p(n);
  iota(p.begin(), p.end(), 0);
  sort(p.begin(), p.end(),
       [](long long a, long long b) { return deg[a] < deg[b]; });
  long long ans = -1;
  for (long long i = 0; i < n; i++) {
    if ((long long)(cur).size() && cur.count(p[i])) dfs(p[i]), ans++;
  }
  cout << ans << '\n';
}
