//CLOCKS_PER_SEC
using namespace std;
#include<bits/stdc++.h>
#define sqr(x) (x)*(x)
//#define sort stable_sort
#define ll long long
#define mk make_pair
#define pb push_back
#define in insert
#define mtr(x,y,z) mk(mk(x,y),z)
#define fi first
#define se second
#define lch(x) ((x)<<1)
#define rch(x) (((x)<<1)|1)
#define all(x) (x).begin(),(x).end()
#define titose CLOCKS_PER_SEC
#define fpi(x) freopen(x,"r",stdin);
#define fpo(x) freopen(x,"w",stdout);
#define fprio fpi("in.txt");fpo("out.txt");
#define fast ios_base::sync_with_stdio(false);
inline void read(int &x){int v=0,f=1;char c=getchar();while (!isdigit(c)&&c!='-') c=getchar();if (c=='-') f=-1; else v=(c&15);while (isdigit(c=getchar())) v=(v<<1)+(v<<3)+(c&15);x=v*f;}
inline void read(ll &x){ll v=0ll,f=1ll;char c=getchar();while (!isdigit(c)&&c!='-') c=getchar();if (c=='-') f=-1; else v=(c&15);while (isdigit(c=getchar())) v=(v<<1)+(v<<3)+(c&15);x=v*f;}
inline void readc(char &x){char c;while (((c=getchar())==' ')||c=='\n');x=c;}
inline void writes(string s){puts(s.c_str());}
inline void writeln(){writes("");}
inline void writei(int x){if (x<0){putchar('-');x=abs(x);}if (!x) putchar('0');char a[25];int top=0;while (x){a[++top]=(x%10)+'0';x/=10;}while (top){putchar(a[top]);top--;}}
inline void writell(ll x){if (x<0){putchar('-');x=abs(x);}if (!x) putchar('0');char a[25];int top=0;while (x){a[++top]=(x%10)+'0';x/=10;}while (top){putchar(a[top]);top--;}}
#define pii pair<int,int>
#define pll pair<ll,ll>
#define vi vector<int>
#define vl vector<ll>
#define si set<int>
#define sl set<ll>
#define mii map<int,int>
#define mll map<ll,ll>
#define msi map<string,int>
#define msl map<string,ll>
#define piii pair<int,pii >
#define piipi pair<pii,int>
#define plll pair<ll,pll >
#define pllpl pair<pll,ll>
#define pqi priority_queue<int>
#define pql priority_queue<ll>
#define npqi priority_queue<int,vector<int>,greater<int> >
#define npql priority_queue<ll,vector<ll>,greater<ll> >
#define forup(i,a,b) for ((i)=(a);(i)<=(b);(i)++)
#define fordo(i,a,b) for ((i)=(a);(i)>=(b);(i)--)
#define rep(i,x) forup ((i),1,(x))
#define repd(i,x) fordo ((i),(x),1)
#define itr iterator
#define fe(itcalc,c) for(__typeof((c).begin()) itcalc=(c).begin();itcalc!=(c).end();itcalc++)
#define NO {cout<<"NO";return 0;}
#define YES {cout<<"YES";return 0;}
#define y0 y000000000000000000000000000
#define y1 y111111111111111111111111111
#define j0 j000000000000000000000000000
#define j1 j111111111111111111111111111
#define cl0(a) memset((a),(0),(sizeof((a))))
#define clz(a) memset((a),(0x16),(sizeof((a))))
#define clf(a) memset((a),(-(0x16)),(sizeof((a))))
#define inf 0x3bbbbbbb
#define lnf 0x1bbbbbbbbbbbbbbbll
#define sqrt divi
#define p2(i) (1ll<<(i))
#define readi read
#define readll read
/*************************************************/
int n,m,i,j,ans,cnt,id[100005],mi=1,fa[100005],vis[100005],t[100005];
vector<int> e[100005];
set<int> s;
int fnd(int x)
{
	if(fa[x]==x) return x;
	return fa[x]=fnd(fa[x]);
}
int main()
{
	scanf("%d%d",&n,&m);
	rep(i,m){
		int x,y;
		scanf("%d%d",&x,&y);
		e[x].pb(y);e[y].pb(x);
	}
	rep(i,n){
		if(e[i].size()<e[mi].size()){
			mi=i;
		}
	}
	rep(i,n){
		fa[i]=i;
	}
	fe(it,e[mi]){
		vis[*it]=1;
	}
	rep(i,n){
		if(!vis[i]){
			fa[fnd(i)]=fnd(mi);
		}
	}
	rep(i,n){
		if(vis[i]){
			id[i]=++cnt;
			t[cnt]=i;
		}
	}
	rep(i,n){
		rep(j,cnt) vis[j]=0;
		fe(it,e[i]){
			if(id[*it]) vis[id[*it]]=1;
		}
		rep(j,cnt)if(!vis[j]){
			fa[fnd(i)]=fnd(t[j]);
		}
	}
	rep(i,n){
		s.in(fnd(i));
	}
	cout<<s.size()-1<<endl;
	return 0;
}


//CLOCKS_PER_SEC
using namespace std;
#include<bits/stdc++.h>
#define sqr(x) (x)*(x)
//#define sort stable_sort
#define ll long long
#define mk make_pair
#define pb push_back
#define in insert
#define mtr(x,y,z) mk(mk(x,y),z)
#define fi first
#define se second
#define lch(x) ((x)<<1)
#define rch(x) (((x)<<1)|1)
#define all(x) (x).begin(),(x).end()
#define titose CLOCKS_PER_SEC
#define fpi(x) freopen(x,"r",stdin);
#define fpo(x) freopen(x,"w",stdout);
#define fprio fpi("in.txt");fpo("out.txt");
#define fast ios_base::sync_with_stdio(false);
inline void read(int &x){int v=0,f=1;char c=getchar();while (!isdigit(c)&&c!='-') c=getchar();if (c=='-') f=-1; else v=(c&15);while (isdigit(c=getchar())) v=(v<<1)+(v<<3)+(c&15);x=v*f;}
inline void read(ll &x){ll v=0ll,f=1ll;char c=getchar();while (!isdigit(c)&&c!='-') c=getchar();if (c=='-') f=-1; else v=(c&15);while (isdigit(c=getchar())) v=(v<<1)+(v<<3)+(c&15);x=v*f;}
inline void readc(char &x){char c;while (((c=getchar())==' ')||c=='\n');x=c;}
inline void writes(string s){puts(s.c_str());}
inline void writeln(){writes("");}
inline void writei(int x){if (x<0){putchar('-');x=abs(x);}if (!x) putchar('0');char a[25];int top=0;while (x){a[++top]=(x%10)+'0';x/=10;}while (top){putchar(a[top]);top--;}}
inline void writell(ll x){if (x<0){putchar('-');x=abs(x);}if (!x) putchar('0');char a[25];int top=0;while (x){a[++top]=(x%10)+'0';x/=10;}while (top){putchar(a[top]);top--;}}
#define pii pair<int,int>
#define pll pair<ll,ll>
#define vi vector<int>
#define vl vector<ll>
#define si set<int>
#define sl set<ll>
#define mii map<int,int>
#define mll map<ll,ll>
#define msi map<string,int>
#define msl map<string,ll>
#define piii pair<int,pii >
#define piipi pair<pii,int>
#define plll pair<ll,pll >
#define pllpl pair<pll,ll>
#define pqi priority_queue<int>
#define pql priority_queue<ll>
#define npqi priority_queue<int,vector<int>,greater<int> >
#define npql priority_queue<ll,vector<ll>,greater<ll> >
#define forup(i,a,b) for ((i)=(a);(i)<=(b);(i)++)
#define fordo(i,a,b) for ((i)=(a);(i)>=(b);(i)--)
#define rep(i,x) forup ((i),1,(x))
#define repd(i,x) fordo ((i),(x),1)
#define itr iterator
#define fe(itcalc,c) for(__typeof((c).begin()) itcalc=(c).begin();itcalc!=(c).end();itcalc++)
#define NO {cout<<"NO";return 0;}
#define YES {cout<<"YES";return 0;}
#define y0 y000000000000000000000000000
#define y1 y111111111111111111111111111
#define j0 j000000000000000000000000000
#define j1 j111111111111111111111111111
#define cl0(a) memset((a),(0),(sizeof((a))))
#define clz(a) memset((a),(0x16),(sizeof((a))))
#define clf(a) memset((a),(-(0x16)),(sizeof((a))))
#define inf 0x3bbbbbbb
#define lnf 0x1bbbbbbbbbbbbbbbll
#define sqrt divi
#define p2(i) (1ll<<(i))
#define readi read
#define readll read
/*************************************************/
int n,m,i,j,ans,a[355][355],cnt,id[100005],mi=1,fa[100005],vis[100005],t[100005];
vector<int> e[355];
set<int> s;
int fnd(int x)
{
	if(fa[x]==x) return x;
	return fa[x]=fnd(fa[x]);
}
int main()
{
	scanf("%d%d",&n,&m);
	rep(i,m){
		int x,y;
		scanf("%d%d",&x,&y);
		e[x].pb(y);e[y].pb(x);
	}
	rep(i,n){
		if(e[i].size()<e[mi].size()){
			mi=i;
		}
	}
	rep(i,n){
		fa[i]=i;
	}
	fe(it,e[mi]){
		vis[*it]=1;
	}
	rep(i,n){
		if(!vis[i]){
			fa[fnd(i)]=fnd(mi);
		}
	}
	rep(i,n){
		if(vis[i]){
			id[i]=++cnt;
			t[cnt]=i;
		}
	}
	rep(i,n){
		rep(j,cnt) vis[j]=0;
		fe(it,e[i]){
			if(id[*it]) vis[id[*it]]=1;
		}
		rep(j,cnt)if(!vis[j]){
			fa[fnd(i)]=fnd(t[j]);
		}
	}
	rep(i,n){
		s.in(fnd(i));
	}
	cout<<s.size()-1<<endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  int x=sqrt(N);
  //int x=N/2-10;
  vector<int>v;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
    else
      v.push_back(i);
  }
  for (int i=0;i+1<(int)v.size();i++)
    merge(v[i],v[i+1]);
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    // if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  //int x=sqrt(N);
  int x=N/2-10;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  //int x=sqrt(N);
  int x=N/2;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  set<int>zero;
  for (int i=1;i<=N;i++){
    map<int,int>mp;
    for (int x:adj[i])
      if (zero.count(root(x)))
	mp[root(x)]++;
    vector<int>v;
    bool merged=false;
    for (int x:zero){
      if (mp[x]!=siz[x]){
	merged=true;
	merge(i,x);
	v.push_back(x);
      }
    }
    for (int x:v){
      zero.erase(x);
      zero.insert(root(x));
    }
    if (!merged)
      zero.insert(i);
  }
  cout<<zero.size()-1<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  int x=sqrt(N);
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()+10>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  int x=sqrt(N);
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  for (int i=0;i<M;i++){
    if (big[a[i]] && big[b[i]] && root(a[i])!=root(b[i])){
      merge(a[i],b[i]);
      ans++;
    }
  }
  cout<<ans<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  //int x=sqrt(N);
  int x=N/2-10;
  x=0;
  vector<int>v;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
    else
      v.push_back(i);
  }
  for (int i=0;i+1<(int)v.size();i++)
    merge(v[i],v[i+1]);
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  int x=sqrt(N);
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  //int x=sqrt(N);
  int x=N/2;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()+10>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  //int x=sqrt(N);
  int x=N/2-10;
  vector<int>v;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
    else
      v.push_back(i);
  }
  for (int i=0;i+1<(int)v.size();i++)
    merge(v[i],v[i+1]);
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  //int x=sqrt(N);
  int x=N/2;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  //int x=sqrt(N);
  int x=N/2-10;
  vector<int>v;
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
    else
      v.push_back(i);
  }
  for (int i=0;i+1<(int)v.size();i++)
    merge(v[i],v[i+1]);
  int ans=0;
  set<int>st;
  for (int i=1;i<=N;i++)
    // if (big[i])
      st.insert(root(i));
  ans=st.size()-1;
  cout<<max(0,ans)<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  int x=sqrt(N);
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()+2>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
    }
    big[i]=true;
  }
  int ans=0;
  for (int i=0;i<M;i++){
    if (big[a[i]] && big[b[i]] && root(a[i])!=root(b[i])){
      merge(a[i],b[i]);
      ans++;
    }
  }
  cout<<ans<<endl;
  return 0;
}


#include <bits/stdc++.h>
using namespace std;

mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
typedef long double ld;
#define INF 2001001001
#define MOD 1000000007

int N,M;
vector<int>adj[100001];
int rt[100001];
bool vis[100001];
bool big[100001];
int siz[100001];

int root(int x){
  while (x!=rt[x]){
    rt[x]=rt[rt[x]];
    x=rt[x];
  }
  return x;
}

void merge(int a, int b){
  a=root(a);
  b=root(b);
  if (a==b) return;
  if (siz[a]<siz[b])
    swap(a,b);
  siz[a]+=siz[b];
  rt[b]=a;
}

int a[100001],b[100001];

int main()
{
  //ios_base::sync_with_stdio(0);cin.tie(0);
  //freopen (".in","r",stdin);
  //freopen (".out","w",stdout);
  cin>>N>>M;
  for (int i=0;i<M;i++){
    cin>>a[i]>>b[i];
    adj[a[i]].push_back(b[i]);
    adj[b[i]].push_back(a[i]);
  }
  for (int i=1;i<=N;i++){
    rt[i]=i;
    siz[i]=1;
  }
  int x=sqrt(N);
  for (int i=1;i<=N;i++){
    if ((int)adj[i].size()+10>=x){
      for (int j=1;j<=N;j++)
	vis[j]=false;
      for (int y:adj[i])
	vis[y]=true;
      for (int j=1;j<=N;j++)
	if (!vis[j])
	  merge(j,i);
      big[i]=true;
    }
  }
  int ans=0;
  for (int i=0;i<M;i++){
    if (big[a[i]] && big[b[i]] && root(a[i])!=root(b[i])){
      merge(a[i],b[i]);
      ans++;
    }
  }
  cout<<ans<<endl;
  return 0;
}


#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#include <utility>
#define llint long long
#define inf 1e18

using namespace std;
typedef pair<llint, llint> P;
typedef pair<llint, P> E;

struct UnionFind{
	int size;
	vector<int> parent;

	UnionFind(){}
	UnionFind(int size){
		this->size = size;
		parent.resize(size+1);
		init();
	}
	void init(){
		for(int i = 0; i <= size; i++) parent[i] = i;
	}
	int root(int i){
		if(parent[i] == i) return i;
		return parent[i] = root(parent[i]);
	}
	bool same(int i, int j){
		return root(i) == root(j);
	}
	void unite(int i, int j){
		int root_i = root(i), root_j = root(j);
		if(root_i == root_j) return;
		parent[root_i] = root_j;
	}
};

llint n, m;
vector<llint> G[100005];
vector<E> vec;
set<P> S;
set<llint> T;
UnionFind uf(100005);

llint calc()
{
	sort(vec.begin(), vec.end());

	llint ret = 0;
	for(int i = 0; i < vec.size(); i++){
		llint w = vec[i].first, u = vec[i].second.first, v = vec[i].second.second;
		if(uf.same(u, v)) continue;
		ret += w;
		uf.unite(u, v);
	}
	return ret;
}

int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m;
	llint u, v;
	for(int i = 1; i <= m; i++){
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
		if(u > v) swap(u, v);
		S.insert(P(u, v));
	}

	if(n <= 400){
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(i >= j) continue;
				if(S.count(P(i, j))) vec.push_back(E(1LL, P(i, j)));
				else vec.push_back(E(0LL, P(i, j)));
			}
		}
		cout << calc() << endl;
		return 0;
	}

	llint mn = inf, mn_v;
	for(int i = 1; i <= n; i++){
		if(mn > (llint)G[i].size()){
			mn = (llint)G[i].size();
			mn_v = i;
		}
	}
	for(int i = 0; i < G[mn_v].size(); i++) T.insert(G[mn_v][i]);

	if(T.size() == 0){
		cout << 0 << endl;
		return 0;
	}

	llint ans;
	for(auto it = T.begin(); it != T.end(); it++){
		for(auto it2 = T.begin(); it2 != T.end(); it2++){
			if(*it >= *it2) continue;
			if(S.count(P(*it, *it2))) vec.push_back(E(1LL, P(*it, *it2)));
			else vec.push_back(E(0LL, P(*it,*it2)));
		}
	}

	llint comp = n - (llint)T.size();
	for(auto it = T.begin(); it != T.end(); it++){
		int v = *it; bool flag = true;
		if(G[v].size() < comp) flag = false;
		int cnt = 0;
		for(int i = 0; i < G[v].size(); i++){
			if(T.count(G[v][i]) == 0) cnt++;
		}
		if(cnt < comp) flag = false;
		if(flag) vec.push_back(E(1LL, P(mn_v, v)));
		else vec.push_back(E(0LL, P(mn_v, v)));
	}
	ans = calc();
	cout << ans << endl;

	return 0;
}


#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#include <utility>
#define llint long long
#define inf 1e18

using namespace std;
typedef pair<llint, llint> P;
typedef pair<llint, P> E;

struct UnionFind{
	int size;
	vector<int> parent;

	UnionFind(){}
	UnionFind(int size){
		this->size = size;
		parent.resize(size+1);
		init();
	}
	void init(){
		for(int i = 0; i <= size; i++) parent[i] = i;
	}
	int root(int i){
		if(parent[i] == i) return i;
		return parent[i] = root(parent[i]);
	}
	bool same(int i, int j){
		return root(i) == root(j);
	}
	void unite(int i, int j){
		int root_i = root(i), root_j = root(j);
		if(root_i == root_j) return;
		parent[root_i] = root_j;
	}
};

llint n, m;
vector<llint> G[100005];
vector<E> vec;
set<P> S;
set<llint> T;
UnionFind uf(100005);

llint calc()
{
	sort(vec.begin(), vec.end());

	llint ret = 0;
	for(int i = 0; i < vec.size(); i++){
		llint w = vec[i].first, u = vec[i].second.first, v = vec[i].second.second;
		if(uf.same(u, v)) continue;
		ret += w;
		uf.unite(u, v);
	}
	return ret;
}

int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m;
	llint u, v;
	for(int i = 1; i <= m; i++){
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
		if(u > v) swap(u, v);
		S.insert(P(u, v));
	}

	if(n <= 400){
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(i >= j) continue;
				if(S.count(P(i, j))) vec.push_back(E(1LL, P(i, j)));
				else vec.push_back(E(0LL, P(i, j)));
			}
		}
		cout << calc() << endl;
		return 0;
	}

	llint mn = inf, mn_v;
	for(int i = 1; i <= n; i++){
		if(mn > (llint)G[i].size()){
			mn = (llint)G[i].size();
			mn_v = i;
		}
	}
	for(int i = 0; i < G[mn_v].size(); i++) T.insert(G[mn_v][i]);

	llint ans;
	for(auto it = T.begin(); it != T.end(); it++){
		for(auto it2 = T.begin(); it2 != T.end(); it2++){
			if(*it >= *it2) continue;
			if(S.count(P(*it, *it2))) vec.push_back(E(1LL, P(*it, *it2)));
			else vec.push_back(E(0LL, P(*it,*it2)));
		}
	}
	ans = calc();

	if((llint)T.size() > 0){
		llint comp = n - (llint)T.size(); bool flag = true;
		for(auto it = T.begin(); it != T.end(); it++){
			int v = *it;
			if(G[v].size() < comp){
				flag = false;
				break;
			}
			int cnt = 0;
			for(int i = 0; i < G[v].size(); i++){
				if(T.count(G[v][i]) == 0) cnt++;
			}
			if(cnt < comp){
				flag = false;
				break;
			}
		}
		if(flag) ans++;
	}
	cout << ans << endl;

	return 0;
}


#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#include <utility>
#define llint long long
#define inf 1e18

using namespace std;
typedef pair<llint, llint> P;
typedef pair<llint, P> E;

struct UnionFind{
	int size;
	vector<int> parent;

	UnionFind(){}
	UnionFind(int size){
		this->size = size;
		parent.resize(size+1);
		init();
	}
	void init(){
		for(int i = 0; i <= size; i++) parent[i] = i;
	}
	int root(int i){
		if(parent[i] == i) return i;
		return parent[i] = root(parent[i]);
	}
	bool same(int i, int j){
		return root(i) == root(j);
	}
	void unite(int i, int j){
		int root_i = root(i), root_j = root(j);
		if(root_i == root_j) return;
		parent[root_i] = root_j;
	}
};

llint n, m;
vector<llint> G[100005];
vector<E> vec;
set<P> S;
set<llint> T;
UnionFind uf(100005);

llint calc()
{
	sort(vec.begin(), vec.end());

	llint ret = 0;
	for(int i = 0; i < vec.size(); i++){
		llint w = vec[i].first, u = vec[i].second.first, v = vec[i].second.second;
		if(uf.same(u, v)) continue;
		ret += w;
		uf.unite(u, v);
	}
	return ret;
}

int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m;
	llint u, v;
	for(int i = 1; i <= m; i++){
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
		if(u > v) swap(u, v);
		S.insert(P(u, v));
	}

	if(n <= 400){
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(i >= j) continue;
				if(S.count(P(i, j))) vec.push_back(E(1LL, P(i, j)));
				else vec.push_back(E(0LL, P(i, j)));
			}
		}
		cout << calc() << endl;
		return 0;
	}

	llint mn = inf, mn_v;
	for(int i = 1; i <= n; i++){
		if(mn > (llint)G[i].size()){
			mn = (llint)G[i].size();
			mn_v = i;
		}
	}
	for(int i = 0; i < G[mn_v].size(); i++) T.insert(G[mn_v][i]);

	if(T.size() == 0){
		cout << 0 << endl;
		return 0;
	}

	llint ans;
	for(auto it = T.begin(); it != T.end(); it++){
		for(auto it2 = T.begin(); it2 != T.end(); it2++){
			if(*it >= *it2) continue;
			if(S.count(P(*it, *it2))) vec.push_back(E(1LL, P(*it, *it2)));
			else vec.push_back(E(0LL, P(*it,*it2)));
		}
	}

	llint comp = n - (llint)T.size();
	for(auto it = T.begin(); it != T.end(); it++){
		int v = *it; bool flag = true;
		if(G[v].size() < comp) flag = false;
		int cnt = 0;
		for(int i = 0; i < G[v].size(); i++){
			if(T.count(G[v][i]) == 0) cnt++;
		}
		if(cnt < comp) flag = false;
		if(flag) vec.push_back(E(1LL, P(mn_v, v)));
		else vec.push_back(E(1LL, P(mn_v, v)));
	}
	ans = calc();
	cout << ans << endl;

	return 0;
}


#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
#include <utility>
#define llint long long

using namespace std;
typedef pair<llint, llint> P;
typedef pair<llint, P> E;

struct UnionFind{
	int size;
	vector<int> parent;

	UnionFind(){}
	UnionFind(int size){
		this->size = size;
		parent.resize(size+1);
		init();
	}
	void init(){
		for(int i = 0; i <= size; i++) parent[i] = i;
	}
	int root(int i){
		if(parent[i] == i) return i;
		return parent[i] = root(parent[i]);
	}
	bool same(int i, int j){
		return root(i) == root(j);
	}
	void unite(int i, int j){
		int root_i = root(i), root_j = root(j);
		if(root_i == root_j) return;
		parent[root_i] = root_j;
	}
};

llint n, m;
vector<llint> G[100005];
vector<E> vec;
set<P> S;
set<llint> T;
UnionFind uf(100005);

llint calc()
{
	sort(vec.begin(), vec.end());

	llint ret = 0;
	for(int i = 0; i < vec.size(); i++){
		llint w = vec[i].first, u = vec[i].second.first, v = vec[i].second.second;
		if(uf.same(u, v)) continue;
		ret += w;
		uf.unite(u, v);
	}
	return ret;
}

int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);

	cin >> n >> m;
	llint u, v;
	for(int i = 1; i <= m; i++){
		cin >> u >> v;
		G[u].push_back(v);
		G[v].push_back(u);
		if(u > v) swap(u, v);
		S.insert(P(u, v));
	}

	if(n <= 400){
		for(int i = 1; i <= n; i++){
			for(int j = 1; j <= n; j++){
				if(i >= j) continue;
				if(S.count(P(i, j))) vec.push_back(E(1LL, P(i, j)));
				else vec.push_back(E(0LL, P(i, j)));
			}
		}
		cout << calc() << endl;
		return 0;
	}

	llint mn = m+1, mn_v;
	for(int i = 1; i <= n; i++){
		if(mn > (int)G[i].size()){
			mn = (int)G[i].size();
			mn_v = i;
		}
	}
	for(int i = 0; i < G[mn_v].size(); i++) T.insert(G[mn_v][i]);

	llint ans;
	for(auto it = T.begin(); it != T.end(); it++){
		for(auto it2 = T.begin(); it2 != T.end(); it2++){
			if(*it >= *it2) continue;
			if(S.count(P(*it, *it2))) vec.push_back(E(1LL, P(*it, *it2)));
			else vec.push_back(E(0LL, P(*it,*it2)));
		}
	}
	ans = calc();

	llint comp = n - (llint)T.size(); bool flag = true;
	for(auto it = T.begin(); it != T.end(); it++){
		int v = *it;
		if(G[v].size() < comp){
			flag = false;
			break;
		}
		int cnt = 0;
		for(int i = 0; i < G[v].size(); i++){
			if(T.count(G[v][i]) == 0) cnt++;
		}
		if(cnt < comp){
			flag = false;
			break;
		}
	}
	if(flag) ans++;
	cout << ans << endl;

	return 0;
}


#include <bits/stdc++.h>
using namespace std;
unordered_set<int> G[100005];
unordered_set<int> V;
int p[100005];
int find(int x){
    return p[x] == x ? x:  p[x] = find(p[x]);
}
void merge(int a, int b){
    a = find(a), b=  find(b);
    if (G[a].size() > G[b].size()) swap(G[a],G[b]);
    //printf("A %d:", a); for (auto x : G[a]) printf("%d ",x);
    //printf("\nB %d:", b);for (auto x : G[b]) printf("%d ",x);
    p[b] = a;
    for (auto it = G[a].begin(); it != G[a].end(); it++){
        if (G[b].find(*it) == G[b].end()){
            //printf("%d %d common %d\n",a,b,*it);
            it = G[a].erase(it);
            if (it == G[a].end()) break;
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].insert(b);
        G[b].insert(a);
    }
    iota(p,p+100005,0);
    for (int i = 1; i <= n; i++){

        for (auto v : V){
            if (G[v].find(i) == G[v].end()){
                merge(v,i);
            }
        }
        if (p[i] == i) V.insert(i);
        for (auto v : V){
            v = find(v);
        }
    }
    printf("%d",V.size()-1);
}


#include <bits/stdc++.h>
using namespace std;
unordered_set<int> G[100005];
unordered_set<int> V;
int p[100005];
int find(int x){
    return p[x] == x ? x:  p[x] = find(p[x]);
}
void merge(int a, int b){
    a = find(a), b=  find(b);
    if (G[a].size() > G[b].size()) swap(G[a],G[b]);
    //printf("A %d:", a); for (auto x : G[a]) printf("%d ",x);
    //printf("\nB %d:", b);for (auto x : G[b]) printf("%d ",x);
    p[b] = a;
    for (auto it = G[a].begin(); it != G[a].end(); it++){
        if (G[b].find(*it) == G[b].end()){
            //printf("%d %d common %d\n",a,b,*it);
            it = G[a].erase(it);
            if (it == G[a].end()) break;
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].insert(b);
        G[b].insert(a);
    }
    iota(p,p+100005,0);
    for (int i = 1; i <= n; i++){

        for (auto v : V){
            if (G[v].find(i) == G[v].end()){
                merge(v,i);
            }
        }
        if (p[i] == i) V.insert(i);
        for (auto v : V){
            if (p[v] != v) V.erase(v);
        }
    }
    printf("%d",V.size()-1);
}


#include <bits/stdc++.h>
using namespace std;
unordered_set<int> G[100005];
vector<int> V;
void merge(int a, int b){
    if (G[a].size() > G[b].size()) swap(G[a],G[b]);
    //printf("A %d:", a); for (auto x : G[a]) printf("%d ",x);
    //printf("\nB %d:", b);for (auto x : G[b]) printf("%d ",x);
    for (auto it = G[a].begin(); it != G[a].end(); it++){
        if (G[b].find(*it) == G[b].end()){
            //printf("%d %d common %d\n",a,b,*it);
            it = G[a].erase(it);
            if (it == G[a].end()) break;
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].insert(b);
        G[b].insert(a);
    }
    for (int i = 1; i <= n; i++){
        for (auto v : V){
            if (G[v].find(i) == G[v].end()){
                merge(v,i);
                goto next;
            }
        }
        V.push_back(i);
        next:;
    }
    printf("%d",V.size()-1);
}


#include <bits/stdc++.h>
using namespace std;
unordered_set<int> G[100005];
unordered_set<int> V;
int p[100005];
int find(int x){
    return p[x] == x ? x:  p[x] = find(p[x]);
}
void merge(int a, int b){
    a = find(a), b=  find(b);
    if (G[a].size() > G[b].size()) swap(G[a],G[b]);
    //printf("A %d:", a); for (auto x : G[a]) printf("%d ",x);
    //printf("\nB %d:", b);for (auto x : G[b]) printf("%d ",x);
    p[b] = a;
    V.erase(b);
    for (auto it = G[a].begin(); it != G[a].end(); it++){
        if (G[b].find(*it) == G[b].end()){
            //printf("%d %d common %d\n",a,b,*it);
            it = G[a].erase(it);
            if (it == G[a].end()) break;
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].insert(b);
        G[b].insert(a);
    }
    iota(p,p+100005,0);
    for (int i = 1; i <= n; i++){

        for (auto v : V){
            if (G[v].find(i) == G[v].end()){
                merge(v,i);
            }
        }
        if (p[i] == i) V.insert(i);
    }
    printf("%d",V.size()-1);
}


#include <bits/stdc++.h>
using namespace std;
unordered_set<int> G[100005];
vector<int> V;
void merge(int a, int b){
    if (G[a].size() > G[b].size()) swap(a,b);
    for (auto it = G[a].begin(); it != G[a].end(); ++it){
        if (G[b].find(*it) == G[b].end()){
            it = G[a].erase(it);
        }
    }
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 0; i < m; i++){
        int a,b;
        scanf("%d%d",&a,&b);
        G[a].insert(b);
        G[b].insert(a);
    }
    for (int i = 1; i <= n; i++){
        for (auto v : V){
            if (G[v].find(i) == G[v].end()){
                merge(v,i);
                goto next;
            }
        }
        V.push_back(i);
        next:;
    }
    printf("%d",V.size()-1);
}


# include <iostream>
# include <cstdio>
# include <vector>
# include <set>
# include <queue>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m, col[maxn];
set<int> exist, path[maxn];

void bfs(int u)
{
	queue<int> q;
	q.push(u);
	exist.erase(u);
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		vector<int> zero;
		for (auto i : exist)
			if (exist.count(i) && path[t].find(i) == path[t].end())
				zero.push_back(i);
		for (auto x : zero) {
			q.push(x);
			exist.erase(x);
		}
	}
	return;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (exist.count(i)) {
			cnt++;
			bfs(i);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


# include <iostream>
# include <cstdio>
# include <vector>
# include <set>
# include <queue>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m;
set<int> exist, path[maxn];
bool vis[maxn];

void bfs(int u)
{
	queue<int> q;
	q.push(u);
	vis[u] = true;
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		vector<int> zero;
		for (int i = 1; i <= n; i++)
			if (!vis[i] && path[t].find(i) == path[t].end())
				zero.push_back(i);
		for (auto x : zero) {
			q.push(x);
			vis[x] = true;
		}
	}
	return;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (!vis[i]) {
			cnt++;
			bfs(i);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


# include <iostream>
# include <cstdio>
# include <set>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m;
set<int> exist, path[maxn];

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (exist.count(i)) {
			cnt++;
			exist.erase(i);
			set<int> zero;
			for (int j = 1; j <= n; j++)
				if (exist.count(j) && path[i].find(j) == path[i].end())
					zero.insert(j);
			for (auto it : zero)
				exist.erase(it);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


# include <iostream>
# include <cstdio>
# include <set>
# include <queue>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m;
set<int> exist, path[maxn];

void bfs(int u)
{
	queue<int> q;
	q.push(u);
	exist.erase(u);
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		for (int i = 1; i <= n; i++)
			if (exist.count(i) && path[t].lower_bound(i) == path[t].end()) {
				q.push(i);
				exist.erase(i);
			}
	}
	return;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (exist.count(i)) {
			cnt++;
			bfs(i);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


# include <iostream>
# include <cstdio>
# include <vector>
# include <set>
# include <queue>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m;
set<int> exist, path[maxn];

void bfs(int u)
{
	queue<int> q;
	q.push(u);
	exist.erase(u);
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		vector<int> zero;
		for (int i = 1; i <= n; i++)
			if (exist.count(i) && path[t].find(i) == path[t].end())
				zero.push_back(i);
		for (auto x : zero) {
			q.push(x);
			exist.erase(x);
		}
	}
	return;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (exist.count(i)) {
			cnt++;
			bfs(i);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


# include <iostream>
# include <cstdio>
# include <vector>
# include <set>
# include <queue>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m, col[maxn];
set<int> exist, path[maxn];

void bfs(int u)
{
	queue<int> q;
	q.push(u);
	exist.erase(u);
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		vector<int> zero;
		for (auto i : exist)
			if (path[t].find(i) == path[t].end())
				zero.push_back(i);
		for (auto x : zero) {
			q.push(x);
			exist.erase(x);
		}
	}
	return;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (exist.count(i)) {
			cnt++;
			bfs(i);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


# include <iostream>
# include <cstdio>
# include <set>
# include <queue>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m;
set<int> exist, path[maxn];

void bfs(int u)
{
	queue<int> q;
	q.push(u);
	exist.erase(u);
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		for (int i = 1; i <= n; i++)
			if (path[t].find(i) == path[t].end()) {
				q.push(i);
				exist.erase(i);
			}
	}
	return;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (exist.count(i)) {
			cnt++;
			bfs(i);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


# include <iostream>
# include <cstdio>
# include <set>
# include <queue>
# include <algorithm>

using namespace std;

const int maxn = 1e5 + 5;
int n, m;
set<int> exist, path[maxn];

void bfs(int u)
{
	queue<int> q;
	q.push(u);
	exist.erase(u);
	while (!q.empty()) {
		auto t = q.front();
		q.pop();
		for (int i = 1; i <= n; i++)
			if (exist.count(i) && path[t].find(i) == path[t].end()) {
				q.push(i);
				exist.erase(i);
			}
	}
	return;
}

int main()
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		int u, v;
		scanf("%d %d", &u, &v);
		path[u].insert(v);
		path[v].insert(u);
	}
	for (int i = 1; i <= n; i++)
		exist.insert(i);
	int cnt = 0;
	for (int i = 1; i <= n; i++)
		if (exist.count(i)) {
			cnt++;
			bfs(i);
		}
	printf("%d\n", cnt - 1);
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
set<int> S;
int sta[M], top;
int in[M];
struct STC{
    int i, v;bool operator<(STC o) const{return v<o.v;}
}p[M];
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        g[x].insert(y);
        g[y].insert(x);
        in[x] ++;
        in[y] ++;
    }
    for(int i=1;i<=n;i++) fa[i] = i, S.insert(i), p[i] = (STC){i, in[i]};
    sort(p+1, p+n+1);
    for(int i=1;i<=n;i++){
        int u = p[i].i;
        if(S.count(u))S.erase(S.find(u));
        top = 0;
        for(auto v : S){
            if(!g[u].count(v)){
                uni(u, v);
                sta[++ top] = v;
            }
        }
        for(int j=1;j<=top;j++) S.erase(S.find(sta[j]));
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
int in[M];
struct STC{
    int i, v;bool operator<(STC o) const{return v<o.v;}
}p[M];
int sta[M], top;
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        g[x].insert(y);
        g[y].insert(x);
        in[x] ++;
        in[y] ++;
    }
    for(int i=1;i<=n;i++) fa[i] = i, p[i] = (STC){i, in[i]};
    sort(p+1, p+n+1);
    int u = p[1].i;
    for(int i=1;i<=n;i++){
        if(!g[u].count(i)){
            uni(u, i);
        }
    }
    sta[++ top] = u;
    for(int i=1;i<=n;i++)if(seek(i)-u)sta[++ top] = i;
    for(int i=1;i<=top;i++){
        for(int j=i+1;j<=top;j++){
            int x = sta[i], y = sta[j];
            if(!g[x].count(y)){
                uni(x, y);
            }
        }
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
int in[M];
struct STC{
    int i, v;bool operator<(STC o) const{return v<o.v;}
}p[M];
int pol[M], ptr;
int sta[M], top;
set<int> S;
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        g[x].insert(y);
        g[y].insert(x);
        in[x] ++;
        in[y] ++;
    }
    for(int i=1;i<=n;i++) fa[i] = i, p[i] = (STC){i, in[i]};
    sort(p+1, p+n+1);
    int u = p[1].i;
    S.insert(u);
    pol[++ ptr] = u;
    for(int i=1;i<=n;i++){
        if(!g[u].count(i)){
            uni(u, i);
            S.insert(i);
            pol[++ ptr] = i;
        }
    }
    for(int i=1;i<=n;i++)if(seek(i)-u)sta[++ top] = i;
    for(int i=1;i<=top;i++){
        int x = sta[i];
        bool flag = false;
        for(int j=1;j<=ptr;j++){
            int v = pol[j];
            if(!g[x].count(v)){flag=true;break;}
        }
        if(flag) uni(u, x);
    }
    for(int i=1;i<=top;i++){
        for(int j=i+1;j<=top;j++){
            int x = sta[i], y = sta[j];
            if(!g[x].count(y)){
                uni(x, y);
            }
        }
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
int in[M];
struct STC{
    int i, v;bool operator<(STC o) const{return v<o.v;}
}p[M];
int sta[M], top;
set<int> S;
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        g[x].insert(y);
        g[y].insert(x);
        in[x] ++;
        in[y] ++;
    }
    for(int i=1;i<=n;i++) fa[i] = i, p[i] = (STC){i, in[i]};
    sort(p+1, p+n+1);
    int u = p[1].i;
    S.insert(u);
    for(int i=1;i<=n;i++){
        if(!g[u].count(i)){
            uni(u, i);
            S.insert(i);
        }
    }
    for(int i=1;i<=n;i++)if(seek(i)-u)sta[++ top] = i;
    for(int i=1;i<=top;i++){
        int x = sta[i];
        bool flag = false;
        for(auto v : g[x]){
            if(!S.count(v)){flag=true;break;}
        }
        if(flag) uni(u, x);
    }
    for(int i=1;i<=top;i++){
        for(int j=i+1;j<=top;j++){
            int x = sta[i], y = sta[j];
            if(!g[x].count(y)){
                uni(x, y);
            }
        }
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
int in[M];
struct STC{
    int i, v;bool operator<(STC o) const{return v<o.v;}
}p[M];
int sta[M], top;
set<int> S;
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        g[x].insert(y);
        g[y].insert(x);
        in[x] ++;
        in[y] ++;
    }
    for(int i=1;i<=n;i++) fa[i] = i, p[i] = (STC){i, in[i]};
    sort(p+1, p+n+1);
    int u = p[1].i;
    S.insert(u);
    for(int i=1;i<=n;i++){
        if(!g[u].count(i)){
            uni(u, i);
            S.insert(i);
        }
    }
    for(int i=1;i<=n;i++)if(seek(i)-u)sta[++ top] = i;
    for(int i=1;i<=top;i++){
        int x = sta[i];
        bool flag = false;
        for(auto v : g[x]){
            if(S.count(v)){flag=true;break;}
        }
        if(flag) uni(u, x);
    }
    for(int i=1;i<=top;i++){
        for(int j=i+1;j<=top;j++){
            int x = sta[i], y = sta[j];
            if(!g[x].count(y)){
                uni(x, y);
            }
        }
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
set<int> S;
int sta[M], top;
int in[M];
struct STC{
    int i, v;bool operator<(STC o) const{return v<o.v;}
}p[M];
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        g[x].insert(y);
        g[y].insert(x);
        in[x] ++;
        in[y] ++;
    }
    for(int i=1;i<=n;i++) fa[i] = i, S.insert(i), p[i] = (STC){i, in[i]};
    sort(p+1, p+n+1);
    for(int i=1;i<=n;i++){
        int u = p[i].i;
        top = 0;
        for(auto v : S){
            if(!g[u].count(v)){
                uni(u, v);
                sta[++ top] = v;
            }
        }
        for(int j=1;j<=top;j++) S.erase(S.find(sta[j]));
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
set<int> S;
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        if(x > y) swap(x, y);
        g[x].insert(y);
    }
    for(int i=1;i<=n;i++) fa[i] = i, S.insert(i);
    for(int i=1;i<=n;i++){
        if(fa[i]==i)
        for(auto j : S){
            if(!g[i].count(j)){
                uni(i, j);
            }
        }
        S.erase(S.find(i));
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


#include<bits/stdc++.h>
using namespace std;
const int M = 1e5+5;
int n, m;
set<int> g[M];
int fa[M];
int seek(int u){return fa[u]==u?u:fa[u]=seek(fa[u]);}
void uni(int x,int y){
    int fx = seek(x), fy = seek(y);
    if(fx-fy){
        fa[fy] = fx;
        seek(fy);
    }
}
int in[M];
struct STC{
    int i, v;bool operator<(STC o) const{return v<o.v;}
}p[M];
int sta[M], top;
set<int> S;
int main(){
    scanf("%d%d", &n, &m);
    for(int i=1;i<=m;i++){
        int x, y;scanf("%d%d", &x, &y);
        g[x].insert(y);
        g[y].insert(x);
        in[x] ++;
        in[y] ++;
    }
    for(int i=1;i<=n;i++) fa[i] = i, p[i] = (STC){i, in[i]};
    sort(p+1, p+n+1);
    int u = p[1].i;
    S.insert(u);
    for(int i=1;i<=n;i++){
        if(!g[u].count(i)){
            uni(u, i);
            S.insert(i);
        }
    }
    for(int i=1;i<=n;i++)if(seek(i)-u)sta[++ top] = i;
    for(int i=1;i<=top;i++){
        int x = sta[i];
        bool flag = true;
        for(auto v : g[x]){
            if(S.count(v)){flag=false;break;}
        }
        if(flag) uni(u, x);
    }
    for(int i=1;i<=top;i++){
        for(int j=i+1;j<=top;j++){
            int x = sta[i], y = sta[j];
            if(!g[x].count(y)){
                uni(x, y);
            }
        }
    }
    int ans = 0;
    for(int i=1;i<=n;i++) ans += (fa[i]==i);
    printf("%d\n", ans-1);
}


/*
Name:
Copyright: No
Author: Gensokyo_Alice
Date:
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, M, ind[MAXN], cnt = 0;

int main() {
	ios::sync_with_stdio(false);
	#ifdef ZZCAKIOI
	#endif
    cin >> N >> M;
    for (ll x, y, i = 1; i <= M; i++) {
        cin >> x >> y;
        ind[y]++;
    }
    for (ll i = 1; i <= N; i++) {
        if (ind[i] == i-1) {
            cnt++;
        }
    }
    cout << cnt-1 << endl;
	return 0;
}


/*
Name:
Copyright: No
Author: Gensokyo_Alice
Date:
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, M, ind[MAXN], fa[MAXN], cnt = 0, siz[MAXN];
vector <ll> q, g[MAXN];
map <ll, ll> m;

ll find_(ll);

int main() {
	ios::sync_with_stdio(false);
	#ifdef ZZCAKIOI
	#endif
    cin >> N >> M;
    for (ll i = 1; i <= N; i++) siz[i]++, fa[i] = i;
    for (ll x, y, i = 1; i <= M; i++) {
        cin >> x >> y;
        if (x < y) swap(x, y);
        g[x].push_back(y);
    }
    for (ll i = 1; i <= N; i++) {
        m.clear();
        for (unsigned int j = 0; j < g[i].size(); j++) m[find_(g[i].at(j))]++;
        for (unsigned int j = 0; j < q.size(); j++) {
            ll fx = find_(i), fy = find_(q.at(j));
            if (fx == fy) continue;
            if (m[fy] < siz[fy]) fa[fx] = fy, siz[fy] += siz[fx];
        }
        if (find_(i) == i) q.push_back(i);
    }
    for (ll i = 1; i <= N; i++)
        if (find_(i) == i) cnt++;
    cout << cnt - 1;
	return 0;
}

ll find_(ll x) {return fa[x] == x ? x : fa[x] = find_(fa[x]);}


/*
Name:
Copyright: No
Author: Gensokyo_Alice
Date:
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;

ll N, M, ind[MAXN], cnt = 0;

int main() {
	ios::sync_with_stdio(false);
	#ifdef ZZCAKIOI
	#endif
    cin >> N >> M;
    for (ll x, y, i = 1; i <= M; i++) {
        cin >> x >> y;
        if (x > y) swap(x, y);
        ind[y]++;
    }
    for (ll i = 1; i <= N; i++) {
        if (ind[i] == i-1) {
            cnt++;
        }
    }
    cout << cnt-1 << endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int n,m;
int num[maxn];
int book[maxn];
vector<int> a[maxn];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        a[x].push_back(y);
        a[y].push_back(x);
    }
    int ans=0;
    int len=0;
    for(int i=1;i<=n;i++)
    {
        //len=0;
        if(book[i]==0)
        {
            //cout<<"begin"<<endl;
            //q.push(i);
            //cout<<i<<endl;
            book[i]=1;
            len++;
            for(int j=0;j<a[i].size();j++)
            {
                int u=a[i][j];
                num[u]++;
            }
            int flag=1;
            while(flag==1)
            {
                flag=0;
                for(int j=1;j<=n;j++)
                {
                    if(book[j]==1)
                        continue;
                    if(num[j]<len)
                    {
                        //cout<<j<<endl;
                        book[j]=1;
                        flag=1;
                        len++;
                        for(int k=0;k<a[j].size();k++)
                        {
                            int u=a[j][k];
                            num[u]++;
                        }
                    }
                }
            }
            ans++;
        }
    }
    printf("%d\n",ans-1);
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
#define INF 0x3f3f3f3f
#define inc(i,x,y) for(int i=x;i<=y;i++)
#define ll long long int
int n,m;
set<int>g[maxn],vis;
bool vv[maxn];
void dfs(int x){
    vv[x]=1;
    vis.erase(x);
    set<int>::iterator it;
    vector<int>v;
    for(it=vis.begin();it!=vis.end();it++){
        int xx=*it;
        if(g[x].count(xx)==0){
            v.push_back(xx);
        }
    }
    for(int i=0;i<v.size();i++){
        vis.erase(v[i]);
    }
    for(int i=0;i<v.size();i++){
        dfs(v[i]);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    int x,y;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        g[x].insert(y);
        g[y].insert(x);
    }
    inc(i,1,n)vis.insert(i);
    int ans=0;
    inc(i,1,n){
        if(vv[i]==0){
            ans++;
            dfs(i);
        }
    }
    printf("%d\n",ans-1);
    return 0;
}


#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXV=1000;
const int INF=100000000;
int n,m,G[MAXV+1][MAXV+1];
int d[MAXV+1];
bool vis[MAXV]={false};
int prim(){
    fill(d,d+MAXV,INF);
    d[1]=0;
    int ans=0;
    for(int i=1;i<=n;i++){
        int u=-1,MIN=INF;
        for(int j=1;j<=n;j++){
                if(vis[j]==false&&d[j]<MIN){
                    u=j;
                    MIN=d[j];
                }        }
        if(u==-1) return -1;
        vis[u]=true;
        ans+=d[u];
        for(int v=1;v<=n;v++){
            if(vis[v]==false&&G[u][v]!=INF&&G[u][v]<d[v]){
                d[v]=G[u][v];
            }
        }
    }
    return ans;
}
    int main(){
        int u,v,w;
        scanf("%d%d",&n,&m);
        fill(G[1],G[1]+MAXV*MAXV,INF);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
            G[i][j]=G[j][i]=0;
        }
        }
        for(int i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            G[u][v]=G[v][u]=1;
        }
        int ans=prim();
        printf("%d\n",ans);
        return 0;
    }


#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9 + 1;

int main() {
#ifdef LOCAL
	freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
#endif
	int n, m;
	cin >> n >> m;
	vector <vector<int>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		a--;
		b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	set <pair<int, int>> blocked;
	for (int i = 0; i < n; i++) {
		blocked.insert({0, i});
	}
	vector <int> now;
	vector <int> usd(n);
	vector <int> cnt(n);
	int ans = 0;
	for (int i = 0; i < n; i++) {
		if (usd[i] == 1) {
			continue;
		}
		ans++;
		now.push_back(i);
		blocked.erase({cnt[i], i});
		cnt[i]++;
		blocked.insert({cnt[i], i});
		for (int j = 0; j < now.size(); j++) {
			usd[now[j]] = 1;
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			for (auto &to : blocked) {
				if (to.first > 0) {
					break;
				}
				now.push_back(to.second);
				blocked.erase({cnt[to.second], to.second});
				cnt[to.second]++;
				blocked.insert({cnt[to.second], to.second});
			}
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]--;
				blocked.insert({cnt[to], to});
			}
		}
		now.clear();
	}
	cout << ans - 1;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9 + 1;

int main() {
#ifdef LOCAL
	freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
#endif
	int n, m;
	cin >> n >> m;
	vector <vector<int>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		a--;
		b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	set <pair<int, int>> blocked;
	for (int i = 0; i < n; i++) {
		blocked.insert({0, i});
	}
	vector <int> now;
	vector <int> usd(n);
	vector <int> cnt(n);
	int ans = 0;
	for (int i = 0; i < n; i++) {
		if (usd[i] == 1) {
			continue;
		}
		ans++;
		now.push_back(i);
		blocked.erase({cnt[i], i});
		cnt[i]++;
		blocked.insert({cnt[i], i});
		for (int j = 0; j < now.size(); j++) {
			assert(now.size() <= n);
			usd[now[j]] = 1;
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			for (auto &to : blocked) {
				if (to.first > 0) {
					break;
				}
				now.push_back(to.second);
				blocked.erase({cnt[to.second], to.second});
				cnt[to.second]++;
				blocked.insert({cnt[to.second], to.second});
			}
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]--;
				blocked.insert({cnt[to], to});
			}
		}
		now.clear();
	}
	cout << ans - 1;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9 + 1;

int main() {
#ifdef LOCAL
	freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
#endif
//
	int n, m;
	cin >> n >> m;
	vector <vector<int>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		a--;
		b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	set <pair<int, int>> blocked;
	for (int i = 0; i < n; i++) {
		blocked.insert({0, i});
	}
	vector <int> now;
	vector <int> usd(n);
	vector <int> cnt(n);
	int ans = 0;
	for (int i = 0; i < n; i++) {
		if (usd[i] == 1) {
			continue;
		}
		ans++;
		now.push_back(i);
		blocked.erase({cnt[i], i});
		cnt[i]++;
		blocked.insert({cnt[i], i});
		for (int j = 0; j < now.size(); j++) {
			usd[now[j]] = 1;
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			for (auto &to : blocked) {
				if (to.first > 0) {
					break;
				}
				now.push_back(to.second);
				blocked.erase({cnt[to.second], to.second});
				cnt[to.second]++;
				blocked.insert({cnt[to.second], to.second});
			}
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]--;
				blocked.insert({cnt[to], to});
			}
		}
		now.clear();
	}
	cout << ans - 1;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9 + 1;

int main() {
#ifdef LOCAL
	freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
#endif
	int n, m;
	cin >> n >> m;
	vector <vector<int>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		a--;
		b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	set <pair<int, int>> blocked;
	for (int i = 0; i < n; i++) {
		blocked.insert({0, i});
	}
	vector <int> now;
	vector <int> usd(n);
	vector <int> cnt(n);
	int ans = 0;
	int l = 0;
	for (int i = 0; i < n; i++) {
		if (usd[i] == 1) {
			continue;
		}
		ans++;
		now.push_back(i);
		blocked.erase({cnt[i], i});
		cnt[i]++;
		blocked.insert({cnt[i], i});
		for (int j = 0; j < now.size(); j++) {
			l++;
			assert(l <= n);
			usd[now[j]] = 1;
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			for (auto &to : blocked) {
				if (to.first > 0) {
					break;
				}
				now.push_back(to.second);
				blocked.erase({cnt[to.second], to.second});
				cnt[to.second]++;
				blocked.insert({cnt[to.second], to.second});
			}
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]--;
				blocked.insert({cnt[to], to});
			}
		}
		now.clear();
	}
	cout << ans - 1;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9 + 1;

int main() {
#ifdef LOCAL
	freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
#endif
//
	int n, m;
	cin >> n >> m;
	vector <vector<int>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		a--;
		b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	set <pair<int, int>> blocked;
	for (int i = 0; i < n; i++) {
		blocked.insert({0, i});
	}
	vector <int> now;
	vector <int> usd(n);
	vector <int> cnt(n);
	int ans = 0;
	for (int i = 0; i < n; i++) {
		if (usd[i] == 1) {
			continue;
		}
		ans++;
		now.push_back(i);
		blocked.erase({cnt[i], i});
		cnt[i]++;
		blocked.insert({cnt[i], i});
		for (int j = 0; j < now.size(); j++) {
			usd[now[j]] = 1;
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			vector <int> p;
			for (auto &to : blocked) {
				if (to.first > 0) {
					break;
				}
				now.push_back(to.second);
				p.push_back(to.second);
			}
			for (auto &to : p) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]--;
				blocked.insert({cnt[to], to});
			}
		}
		now.clear();
	}
	cout << ans - 1;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9 + 1;

int main() {
#ifdef LOCAL
	freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
#endif
	int n, m;
	cin >> n >> m;
	vector <vector<int>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		a--;
		b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	set <pair<int, int>> blocked;
	for (int i = 0; i < n; i++) {
		blocked.insert({0, i});
	}
	vector <int> now;
	vector <int> usd(n);
	vector <int> cnt(n);
	int ans = 0;
	set <int> p;
	for (int i = 0; i < n; i++) {
		if (usd[i] == 1) {
			continue;
		}
		ans++;
		now.push_back(i);
		blocked.erase({cnt[i], i});
		cnt[i]++;
		blocked.insert({cnt[i], i});
		for (int j = 0; j < now.size(); j++) {
			assert(p.find(now[j]) == p.end());
			p.insert(now[j]);
			usd[now[j]] = 1;
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			for (auto &to : blocked) {
				if (to.first > 0) {
					break;
				}
				now.push_back(to.second);
				blocked.erase({cnt[to.second], to.second});
				cnt[to.second]++;
				blocked.insert({cnt[to.second], to.second});
			}
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]--;
				blocked.insert({cnt[to], to});
			}
		}
		now.clear();
	}
	cout << ans - 1;
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

const int INF = 1e9 + 1;

int main() {
#ifdef LOCAL
	freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
#else
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
#endif
	int n, m;
	cin >> n >> m;
	vector <vector<int>> g(n);
	for (int i = 0; i < m; i++) {
		int a, b;
		cin >> a >> b;
		a--;
		b--;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	set <pair<int, int>> blocked;
	for (int i = 0; i < n; i++) {
		blocked.insert({0, i});
	}
	vector <int> now;
	vector <int> usd(n);
	vector <int> cnt(n);
	int ans = 0;
	int l = 0;
	for (int i = 0; i < n; i++) {
		if (usd[i] == 1) {
			continue;
		}
		ans++;
		now.push_back(i);
		blocked.erase({cnt[i], i});
		cnt[i]++;
		blocked.insert({cnt[i], i});
		for (int j = 0; j < now.size(); j++) {
			l++;
			assert(l <= n);
			p.insert(now[j]);
			usd[now[j]] = 1;
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]++;
				blocked.insert({cnt[to], to});
			}
			for (auto &to : blocked) {
				if (to.first > 0) {
					break;
				}
				now.push_back(to.second);
				blocked.erase({cnt[to.second], to.second});
				cnt[to.second]++;
				blocked.insert({cnt[to.second], to.second});
			}
			for (auto &to : g[now[j]]) {
				blocked.erase({cnt[to], to});
				cnt[to]--;
				blocked.insert({cnt[to], to});
			}
		}
		now.clear();
	}
	cout << ans - 1;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
struct node{int to,next;}e[N<<1];
int n,m,head[N],cnt,used[N],hav[N],tims;
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
int main()
{
	scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));int ans=0;
	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(int x=1;x<=n;x++)if(!used[x])
	{
		int flag = 0; tims ++;
		for(int i=head[x];i!=-1;i=e[i].next)hav[e[i].to] = tims;
		for(int i=1;i<=n;i++)if(hav[i] != tims)used[i] = 1;
	}
	printf("%d\n",tims-1);
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
struct node{int to,next;}e[N<<1];
int head[N],cnt;
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
set<int > rot , tmp;
int n,m,fa[N],k,sta[N],top;
vector<int >bel[N];
bool check(int x)
{
	for(int i=0;i<bel[x].size();i++)
		if(!tmp.count(bel[x][i]))return 0;
	return 1;
}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void uni(int x,int y)
{
	if(bel[x].size()>bel[y].size())swap(x,y);
	for(int i=0;i<bel[x].size();i++)
		bel[y].push_back(bel[x][i]);
	fa[x] = y , rot.erase(x);
}
int main()
{
	scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));
	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(int i=1;i<=n;i++)
		rot.insert(i),bel[i].push_back(i);
	for(int i=1;i<=n;i++)fa[i] = i;
	for(int x=1;x<=n;x++)
	{
		tmp.clear();
		for(int i=head[x];i!=-1;i=e[i].next)tmp.insert(e[i].to);
		int now = 0 , fx = find(x); top = 0;
		for(auto it = rot.begin();it!=rot.end();it++)
			sta[++top] = *it;
		for(int k=1;k<=top;k++)
		{
			if(sta[k] == (fx=find(fx)))continue;
			if(check(sta[k]))continue;
			uni(fx,sta[k]);
		}
	}
	int cnt=0;
	for(int i=1;i<=n;i++)cnt+=(fa[i]==i);
	printf("%d\n",cnt-1);
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
struct node{int to,next;}e[N<<1];
int n,m,head[N],cnt,d[N],idx[N],fa[N],used[N],hav[N],tims;
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;d[x]++;}
bool cmp(int x,int y){return d[x]<d[y];}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
	scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));int ans=0;
	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(int i=1;i<=n;i++)idx[i] = i , fa[i] = i;sort(idx+1,idx+n+1,cmp);
	for(int j=1;j<=n;j++)if(!used[idx[j]])
	{
		int x = idx[j] , flag = 0; tims ++;
		for(int i=head[x];i!=-1;i=e[i].next)hav[e[i].to] = tims;
		for(int i=1;i<=n;i++)
		{
			if(hav[i] != tims)
				if(used[i]) flag = 1;
				else used[i] = 1;
		}
		if(!flag)ans++;
	}
	printf("%d\n",ans-1);
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
struct node{int to,next;}e[N<<1];
int n,m,head[N],cnt,d[N],idx[N],fa[N],used[N];
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;d[x]++;}
bool cmp(int x,int y){return d[x]<d[y];}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
	scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));int ans=0;
	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(int i=1;i<=n;i++)idx[i] = i , fa[i] = i;sort(idx+1,idx+n+1,cmp);
	for(int j=1;j<=n;j++)
	{
		int x = idx[j] , num = 0;
		for(int i=head[x];i!=-1;i=e[i].next)
			if(used[e[i].to])num++;
		if(num&&num==j-1)ans++; used[x] = 1;
	}
	printf("%d\n",ans);
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
struct node{int to,next;}e[N<<1];
int n,m,head[N],cnt,used[N],hav[N],tims,vis[N];
queue<int >q;
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
int main()
{
	scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));int ans=0;
	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(int i=2;i<=n;i++)q.push(i); used[1] = 1;
	while(!q.empty())
	{
		int x = q.front() , flag = 0 ; q.pop(); if(used[x])continue;
		if(vis[x])ans++ , flag = 1; vis[x] = 1;
		tims ++;
		for(int i=head[x];i!=-1;i=e[i].next)hav[e[i].to] = tims;
		for(int i=1;i<=n;i++)
			if(hav[i] != tims) if(used[i]) flag = 1;
		if(!flag)q.push(x);
		else
		{
			for(int i=1;i<=n;i++)
				if(hav[i] != tims) used[i] = 1;
		}
	}
	printf("%d\n",ans);
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100005;
struct node{int to,next;}e[N<<1];
int n,m,head[N],cnt,used[N],hav[N],tims;
void add(int x,int y){e[cnt]=(node){y,head[x]};head[x]=cnt++;}
int main()
{
	scanf("%d%d",&n,&m);memset(head,-1,sizeof(head));int ans=0;
	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
	for(int x=1;x<=n;x++)if(!used[x])
	{
		int flag = 0; tims ++;
		for(int i=head[x];i!=-1;i=e[i].next)
			hav[e[i].to] = tims;
		for(int i=1;i<=n;i++)
			if(hav[i] != tims)
			{
				if(used[i]) flag = 1;
				else used[i] = 1;
			}
		if(!flag)ans++;
	}
	printf("%d\n",ans-1);
}


#include<bits/stdc++.h>
#include<iostream>
#include <iomanip>
#include<math.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define fi first
#define se second
#define gap ' '
#define abs(x) ((x)>0?(x):-(x))
#define INF 1e18
#define mod 1000000007
#define inf 1e9
#define pi 3.14159265358979
ll powr(ll m,ll n)
{
    if(m==1)
        return 1;
    if(n==0)
        return 1;
    if(n==1)
        return m%mod;
    if(n%2)
    {
        ll te=powr(m,n/2);
        return (((te*te)%mod)*(m%mod))%mod;
    }
    else
    {
        ll te=powr(m,n/2);
        return (te*te)%mod;
    }
}
set<int> s;
set<int> v[100005];
int vis[100005];
void bfs(int n)
{
    queue<int> q;
    q.push(n);
    while(!q.empty())
    {
        int tmp=q.front();
        vis[tmp]=1;
        q.pop();
        auto it2=s.begin();
        for( auto it=v[tmp].begin(); it!=v[tmp].end(); it++)
        {
            if(it2!=s.end() && *it>(*it2) )
            {
                while(*it>(*it2))
                {
                    q.push(*it2);
                    vis[*it2]=1;
                    s.erase(it2);
                    if(s.empty())
                        return;
                    it2=s.begin();
                }
                //it--;
            }
             if( it2!=s.end() && *it==(*it2))
                it2++;

        }
        vector<int> xtra;
        for(auto it3=s.begin() ;it3!=it2;it3++)
        {
            xtra.pb(*it3);

        }
        for( ;it2!=s.end();it2++)
            vis[*it2]=1;
        s.clear();
        for(int i=0;i<xtra.size();i++)
            s.insert(xtra[i]);
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int tc=1;
    //cin>>tc;
    int cs=0;

    while(tc--)
    {

        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            s.insert(i);
        for(int i=0; i<m; i++)
        {
            int a,b;
            cin>>a>>b;
            v[a].insert(b);
            v[b].insert(a);
        }
        if(m==0)
        {
            cout<<0;
            return 0;
        }
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                bfs(i);
                ans++;
               // cout<<i<<gap;
            }
        }
        cout<<ans-1;
    }

}


#include<bits/stdc++.h>
#include<iostream>
#include <iomanip>
#include<math.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define fi first
#define se second
#define gap ' '
#define abs(x) ((x)>0?(x):-(x))
#define INF 1e18
#define mod 1000000007
#define inf 1e9
#define pi 3.14159265358979
ll powr(ll m,ll n)
{
    if(m==1)
        return 1;
    if(n==0)
        return 1;
    if(n==1)
        return m%mod;
    if(n%2)
    {
        ll te=powr(m,n/2);
        return (((te*te)%mod)*(m%mod))%mod;
    }
    else
    {
        ll te=powr(m,n/2);
        return (te*te)%mod;
    }
}
set<int> s;
set<int> v[100005];
int vis[100005];
void bfs(int n)
{
    queue<int> q;
    q.push(n);
    while(!q.empty())
    {
        int tmp=q.front();
        vis[tmp]=1;
        q.pop();
        auto it2=s.begin();
        for( auto it=v[tmp].begin(); it!=v[tmp].end(); it++)
        {
            if(it2!=s.end() && *it>(*it2) )
            {
                while(*it>(*it2))
                {
                    q.push(*it2);
                    vis[*it2]=1;
                    s.erase(it2);
                    if(s.empty())
                        return;
                    it2=s.begin();
                }
                //it--;
            }
             if( it2!=s.end() && *it==(*it2))
                it2++;

        }
        for( ;it2!=s.end();it2++)
        {
            q.push(*it2);
            vis[*it2]=1;
            s.erase(it2);

        }
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int tc=1;
    //cin>>tc;
    int cs=0;

    while(tc--)
    {

        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            s.insert(i);
        for(int i=0; i<m; i++)
        {
            int a,b;
            cin>>a>>b;
            v[a].insert(b);
            v[b].insert(a);
        }
        if(m==0)
        {
            cout<<0;
            return 0;
        }
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                bfs(i);
                ans++;
                cout<<i<<gap;
            }
        }
        cout<<ans-1;
    }

}


#include<bits/stdc++.h>
#include<iostream>
#include <iomanip>
#include<math.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define fi first
#define se second
#define gap ' '
#define abs(x) ((x)>0?(x):-(x))
#define INF 1e18
#define mod 1000000007
#define inf 1e9
#define pi 3.14159265358979
ll powr(ll m,ll n)
{
    if(m==1)
        return 1;
    if(n==0)
        return 1;
    if(n==1)
        return m%mod;
    if(n%2)
    {
        ll te=powr(m,n/2);
        return (((te*te)%mod)*(m%mod))%mod;
    }
    else
    {
        ll te=powr(m,n/2);
        return (te*te)%mod;
    }
}
set<int> s;
set<int> v[100005];
int vis[100005];
void bfs(int n)
{
    queue<int> q;
    q.push(n);
    while(!q.empty())
    {
        int tmp=q.front();
        vis[tmp]=1;
        q.pop();
        auto it2=s.begin();
        for( auto it=v[tmp].begin(); it!=v[tmp].end(); it++)
        {
            if(it2!=s.end() && *it>(*it2) )
            {
                while(*it>(*it2))
                {
                    q.push(*it2);
                    vis[*it2]=1;
                    s.erase(it2);
                    if(s.empty())
                        return;
                    it2=s.begin();
                }
                //it--;
            }
             if( it2!=s.end() && *it==(*it2))
                it2++;

        }

        for( ;it2!=s.end();it2++)
        {
            q.push(*it2);
            vis[*it2]=1;
            s.erase(it2);
            if(it2==s.end()) break;

        }
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int tc=1;
    //cin>>tc;
    int cs=0;

    while(tc--)
    {

        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            s.insert(i);
        for(int i=0; i<m; i++)
        {
            int a,b;
            cin>>a>>b;
            v[a].insert(b);
            v[b].insert(a);
        }
        if(m==0)
        {
            cout<<0;
            return 0;
        }
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                bfs(i);
                ans++;
               // cout<<i<<gap;
            }
        }
        cout<<ans-1;
    }

}


#include<bits/stdc++.h>
#include<iostream>
#include <iomanip>
#include<math.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define fi first
#define se second
#define gap ' '
#define abs(x) ((x)>0?(x):-(x))
#define INF 1e18
#define mod 1000000007
#define inf 1e9
#define pi 3.14159265358979
ll powr(ll m,ll n)
{
    if(m==1)
        return 1;
    if(n==0)
        return 1;
    if(n==1)
        return m%mod;
    if(n%2)
    {
        ll te=powr(m,n/2);
        return (((te*te)%mod)*(m%mod))%mod;
    }
    else
    {
        ll te=powr(m,n/2);
        return (te*te)%mod;
    }
}
set<int> s;
set<int> v[100005];
int vis[100005];
void bfs(int n)
{
    queue<int> q;
    q.push(n);
    while(!q.empty())
    {
        int tmp=q.front();
        vis[tmp]=1;
        q.pop();
        auto it2=s.begin();
        for( auto it=v[tmp].begin(); it!=v[tmp].end(); it++)
        {
            if(it2!=s.end() && *it>(*it2) )
            {
                while(*it>(*it2))
                {
                    q.push(*it2);
                    vis[*it2]=1;
                    s.erase(it2);
                    if(s.empty())
                        return;
                    it2=s.begin();
                }
                //it--;
            }
             if( it2!=s.end() && *it==(*it2))
                it2++;

        }
        for( ;it2!=s.end();it2++)
        {
            q.push(*it2);
            vis[*it2]=1;
            s.erase(it2);

        }
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int tc=1;
    //cin>>tc;
    int cs=0;

    while(tc--)
    {

        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            s.insert(i);
        for(int i=0; i<m; i++)
        {
            int a,b;
            cin>>a>>b;
            v[a].insert(b);
            v[b].insert(a);
        }
        if(m==0)
        {
            cout<<0;
            return 0;
        }
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                bfs(i);
                ans++;
               // cout<<i<<gap;
            }
        }
        cout<<ans-1;
    }

}


#include<bits/stdc++.h>
#include<iostream>
#include <iomanip>
#include<math.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define fi first
#define se second
#define gap ' '
#define abs(x) ((x)>0?(x):-(x))
#define INF 1e18
#define mod 1000000007
#define inf 1e9
#define pi 3.14159265358979
ll powr(ll m,ll n)
{
    if(m==1)
        return 1;
    if(n==0)
        return 1;
    if(n==1)
        return m%mod;
    if(n%2)
    {
        ll te=powr(m,n/2);
        return (((te*te)%mod)*(m%mod))%mod;
    }
    else
    {
        ll te=powr(m,n/2);
        return (te*te)%mod;
    }
}
set<int> s;
set<int> v[100005];
int vis[100005];
void bfs(int n)
{
    queue<int> q;
    q.push(n);
    s.erase(n);
    vector<int> taken;
    while(!q.empty())
    {
        int tmp=q.front();
        q.pop();
        for(int x:s)
        {
            if(v[tmp].find(x)==v[tmp].end())
            {
                q.push(x);
                taken.pb(x);
            }
        }
        for(int i=0;i<taken.size();i++)
            s.erase(taken[i]);
        taken.clear();
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int tc=1;
    //cin>>tc;
    int cs=0;

    while(tc--)
    {

        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            s.insert(i);
        for(int i=0; i<m; i++)
        {
            int a,b;
            cin>>a>>b;
            v[a].insert(b);
            v[b].insert(a);
        }
        if(m==0)
        {
            cout<<0;
            return 0;
        }
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            if(s.find(i)!=s.end())
            {
                bfs(i);
                ans++;
                // cout<<i<<gap;
            }
        }
        cout<<ans-1;
    }

}


#include<bits/stdc++.h>
#include<iostream>
#include <iomanip>
#include<math.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define fi first
#define se second
#define gap ' '
#define abs(x) ((x)>0?(x):-(x))
#define INF 1e18
#define mod 1000000007
#define inf 1e9
#define pi 3.14159265358979
ll powr(ll m,ll n)
{
    if(m==1)
        return 1;
    if(n==0)
        return 1;
    if(n==1)
        return m%mod;
    if(n%2)
    {
        ll te=powr(m,n/2);
        return (((te*te)%mod)*(m%mod))%mod;
    }
    else
    {
        ll te=powr(m,n/2);
        return (te*te)%mod;
    }
}
set<int> s;
set<int> v[100005];
int vis[100005];
void bfs(int n)
{
    queue<int> q;
    q.push(n);
    while(!q.empty())
    {
        int tmp=q.front();
        vis[tmp]=1;
        q.pop();
        auto it2=s.begin();
        for( auto it=v[tmp].begin(); it!=v[tmp].end(); it++)
        {
            if(it2!=s.end() && *it>(*it2) )
            {
                while(*it>(*it2))
                {
                    q.push(*it2);
                    vis[*it2]=1;
                    s.erase(it2);
                    if(s.empty())
                        return;
                    it2=s.begin();
                }
                //it--;
            }
            if( it2!=s.end() && *it==(*it2))
                it2++;

        }
        vector<int> xtra;
        if(!v[tmp].empty())
        {
            int last=*(--v[tmp].end());
            auto it3=s.upper_bound(last);
            for(auto it4=s.begin() ; it4!=it3; it4++)
            {
                xtra.pb(*it4);

            }
            for( ; it3!=s.end(); it3++)
                vis[*it3]=1;
            s.clear();
            for(int i=0; i<xtra.size(); i++)
                s.insert(xtra[i]);
        }

    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int tc=1;
    //cin>>tc;
    int cs=0;

    while(tc--)
    {

        int n,m;
        cin>>n>>m;
        for(int i=1; i<=n; i++)
            s.insert(i);
        for(int i=0; i<m; i++)
        {
            int a,b;
            cin>>a>>b;
            v[a].insert(b);
            v[b].insert(a);
        }
        if(m==0)
        {
            cout<<0;
            return 0;
        }
        int ans=0;
        for(int i=1; i<=n; i++)
        {
            if(!vis[i])
            {
                bfs(i);
                ans++;
                // cout<<i<<gap;
            }
        }
        cout<<ans-1;
    }

}


#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
	x=0;char ch=1;int fh;
	while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
	if(ch=='-') ch=getchar(),fh=-1;
	else fh=1;
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=fh;
}

const int maxn=100007;

int n,m;
map <int,int> mp;
vector <int> G[maxn],v;
int fa[maxn],val[maxn];
int ans;

int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}

int main(){
	read(n);read(m);
	for(int i=1;i<=n;i++) fa[i]=i,val[i]=1;
	for(int i=1,x,y;i<=m;i++){
		read(x);read(y);
		G[max(x,y)].push_back(min(x,y));
	}
	for(int i=1;i<=n;i++){
		mp.clear();
		for(int j=0;j<G[i].size();j++) mp[find(G[i][j])]++;
		for(int j=0;j<v.size();j++){
			int x=find(i),y=find(v[j]);
			if(x==y) continue;
			if(mp[y]<val[y]) fa[x]=y,val[y]+=val[x];
		}
		if(find(i)==i) v.push_back(i);
	}
	for(int i=1;i<=n;i++) if(find(i)==i) ++ans;
	printf("%d\n",--ans);
	return 0;
}


#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
	x=0;char ch=1;int fh;
	while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
	if(ch=='-') ch=getchar(),fh=-1;
	else fh=1;
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=fh;
}

const int maxn=100007;

int n,m;
map <int,int> mp;
vector <int> G[maxn],v;
int fa[maxn],val[maxn];
int ans;

int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}

int main(){
	read(n);read(m);
	for(int i=1;i<=n;i++) fa[i]=i,val[i]=1;
	for(int i=1,x,y;i<=m;i++){
		read(x);read(y);//
		G[max(x,y)].push_back(min(x,y));
	}
	for(int i=1;i<=n;i++){
		mp.clear();
		for(int j=0;j<G[i].size();j++) mp[find(G[i][j])]++;
		for(int j=0;j<v.size();j++){
			int x=find(i),y=find(v[j]);
			if(x==y) continue;
			if(mp[y]<val[y]) fa[x]=y,val[y]+=val[x];
		}
		if(find(i)==i) v.push_back(i);
	}
	for(int i=1;i<=n;i++) if(find(i)==i) ++ans;
	printf("%d\n",--ans);
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
map<int,int>ma;
vector<int>e[N],b;
int n,m,tot,f[N],s[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        f[i]=i,s[i]=1;
    for(int i=1;i<=m;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        if(u<v) swap(u,v);
        e[u].push_back(v);
    }
    for(int u=1;u<=n;u++)
    {
        ma.clear();
        for(auto v:e[u])
            ma[find(v)]++;
        for(auto v:b)
        {
            int x=find(u),y=find(v);
            if(x==y) continue;
            if(ma[y]<s[y])
                f[x]=y,s[y]+=s[x];
        }
        if(find(u)==u) b.push_back(u);
    }
    int ans=0;
    for(int i=1;i<=n;i++)
        if(f[i]==i)
            ans++;
    cout<<ans-1<<endl;
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
const int mod=1e9+7;
const int maxn=100010;
vector<int>G[maxn];
int fa[maxn];
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main()
{
    #ifdef local
    freopen("a.in","r",stdin);
    #endif // local
    int n,m,u,v;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;++i) fa[i]=i,G[i].clear();
        for(int i=0;i<m;++i){
            scanf("%d%d",&u,&v);
            G[u].emplace_back(v);
            G[v].emplace_back(u);
        }
        for(int i=1;i<=n;++i){
            G[i].emplace_back(i);
            sort(G[i].begin(),G[i].end());
            int x=1;
            for(int j=0;j<G[i].size();++j){
                if(G[i][j]!=x) break;
                ++x;
            }
            if(x<=n) fa[find(i)]=find(x);
        }
        int ans=-1;
        for(int i=1;i<=n;++i) if(find(i)==i) ++ans;
        printf("%d\n",ans);
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
const int mod=1e9+7;
const int maxn=100010;
struct E
{
    int to,next;
}edge[maxn];
int head[maxn],tol;
inline void Addedge(int u,int v)
{
    edge[tol].to=v;edge[tol].next=head[u];head[u]=tol++;
}
int fa[maxn],cnt[maxn],sz[maxn],a[maxn],b[maxn];
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
inline void unite(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx==fy) return;
    sz[fx]+=sz[fy];
    fa[fy]=fx;
}
int main()
{
    #ifdef local
    freopen("a.in","r",stdin);
    #endif // local
    int n,m,u,v;
    while(~scanf("%d%d",&n,&m)){
        memset(head,-1,sizeof(head));
        tol=0;
        for(int i=0;i<m;++i){
            scanf("%d%d",&u,&v);
            if(v>u) swap(u,v);
            Addedge(u,v);
        }
        int *x=a,*y=b,xtop=0,ytop=0;
        for(u=1;u<=n;++u){
            fa[u]=u;
            sz[u]=1;
            for(int i=0;i<xtop;++i) cnt[x[i]]=0;
            for(int i=head[u];i!=-1;i=edge[i].next){
                v=edge[i].to;
                ++cnt[find(v)];
            }
            ytop=0;
            for(int i=0;i<xtop;++i){
                if(cnt[x[i]]<sz[x[i]]) unite(u,x[i]);
                else y[ytop++]=x[i];
            }
            y[ytop++]=u;
            swap(x,y);
            swap(xtop,ytop);
        }
        int ans=-1;
        for(int i=1;i<=n;++i) if(find(i)==i) ++ans;
        printf("%d\n",ans);
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
const int mod=1e9+7;
const int maxn=100010;
vector<int>G[maxn];
int fa[maxn];
int main()
{
    #ifdef local
    freopen("a.in","r",stdin);
    #endif // local
    int n,m,u,v;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;++i) fa[i]=i,G[i].clear();
        for(int i=0;i<m;++i){
            scanf("%d%d",&u,&v);
            if(u<v) swap(u,v);
            G[u].emplace_back(v);
        }
        for(int i=1;i<=n;++i){
            sort(G[i].begin(),G[i].end());
            int x=1;
            for(int j=0;j<G[i].size();++j){
                if(G[i][j]!=x) break;
                ++x;
            }
            fa[i]=x;
        }
        int ans=-1;
        for(int i=1;i<=n;++i) if(fa[i]==i) ++ans;
        printf("%d\n",ans);
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
const int mod=1e9+7;
const int maxn=100010;
int U[maxn<<3],tot;
vector<int>vec[maxn],G[maxn<<3];
bool vis[maxn<<3];
inline void build(int l,int r,int rt)
{
    G[U[rt]=++tot].clear();
    if(l==r){
        G[U[rt]].emplace_back(l);
        return;
    }
    int mid=l+r>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    G[U[rt]].emplace_back(U[rt<<1]);
    G[U[rt]].emplace_back(U[rt<<1|1]);
}
inline void update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l&&R>=r){
        G[v].emplace_back(U[rt]);
        return;
    }
    int mid=l+r>>1;
    if(L<=mid) update(L,R,v,l,mid,rt<<1);
    if(R>mid) update(L,R,v,mid+1,r,rt<<1|1);
    return;
}
inline void dfs(int u)
{
    vis[u]=1;
    for(int v:G[u]){
        if(!vis[v]) dfs(v);
    }
    return;
}
int main()
{
    #ifdef local
    freopen("a.in","r",stdin);
    #endif // local
    int n,m,u,v;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;++i) vec[i].clear(),G[i].clear();
        tot=n;
        build(1,n,1);
        for(int i=0;i<m;++i){
            scanf("%d%d",&u,&v);
            vec[u].emplace_back(v);
            vec[v].emplace_back(u);
        }
        for(int i=1;i<=n;++i){
            vec[i].emplace_back(n+1);
            sort(vec[i].begin(),vec[i].end());
            int last=0;
            for(int j=0;j<vec[i].size();++j){
                if(vec[i][j]-last>1){
                    update(last+1,vec[i][j]-1,i,1,n,1);
                }
                last=vec[i][j];
            }
        }
        memset(vis,0,sizeof(vis));
        int ans=-1;
        for(int i=1;i<=n;++i) if(!vis[i]) dfs(i),++ans;
        printf("%d\n",ans);
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
typedef pair<ll,ll> pll;
const int mod=1e9+7;
const int maxn=100010;
vector<int>G[maxn];
int fa[maxn];
inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main()
{
    #ifdef local
    freopen("a.in","r",stdin);
    #endif // local
    int n,m,u,v;
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;++i) fa[i]=i,G[i].clear();
        for(int i=0;i<m;++i){
            scanf("%d%d",&u,&v);
            if(u<v) swap(u,v);
            G[u].emplace_back(v);
        }
        for(int i=1;i<=n;++i){
            sort(G[i].begin(),G[i].end());
            int x=1;
            for(int j=0;j<G[i].size();++j){
                if(G[i][j]!=x) break;
                ++x;
            }
            fa[find(i)]=find(x);
        }
        int ans=-1;
        for(int i=1;i<=n;++i) if(find(i)==i) ++ans;
        printf("%d\n",ans);
    }
    return 0;
}