#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int n, m, ans, cnt, d[N], minn = INT_MAX, head[N];
int siz[N], fa[N];
bool vis[N], is1[N];
struct Edge
{
int to, nxt;
}edge[N];
void addEdge(int u, int v)
{
edge[++cnt].to = v;
edge[cnt].nxt = head[u];
head[u] = cnt;
d[u]++;
d[v]++;
return;
}
int find(int x)
{
if(x == fa[x]) return x;
else return fa[x] = find(fa[x]);
}
void insert(int x, int y)
{
x = find(x), y = find(y);
if(x == y) return;
if(siz[x]<siz[y])
{
swap(x, y);
}
fa[y] = x;
siz[x] += siz[y];
return;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
{
fa[i] = i;
}
int u, v;
for(int i = 1; i <= m; i++)
{
cin >> u >> v;
addEdge(u, v);
addEdge(v, u);
}
for(int i = 1; i <= n; i++)
{
if(d[i] < minn)
{
minn = i;
}
}
for(int i = head[minn]; i; i = edge[i].nxt)
{
is1[edge[i].to] = 1;
}
for(int i = 1; i <= n; i++)
{
if(is1[i] == 0)
{
insert(minn, i);
}
}
for(int i = 1; i <= n; i++)
{
if(find(minn) == find(i))
continue;
for(int k = 1; k <= n; k++)
{
is1[k] = 0;
}
for(int k = head[i]; k; k = edge[k].nxt)
{
is1[edge[k].to] = 1;
}
for(int j = 1; j <= n; j++)
{
if(is1[j] == 0)
{
insert(i, j);
}
}
}
queue<int> q;
q.push(minn);
while(!q.empty())
{
int pos = q.front();
q.pop();
if(vis[pos]) continue;
vis[pos] = 1;
for(int i = head[pos]; i; i = edge[i].nxt)
{
int to = edge[i].to;
if(find(minn) == find(to))
{
continue;
}
ans++;
insert(minn, to);
if(!vis[to])
{
q.push(to);
}
}
}
cout << ans;
return 0;
}