#include<bits/stdc++.h>
using namespace std;
///------------input------------//
#define fi freopen("in.txt","r",stdin)
#define fo freopen("out.txt","w",stdout)
#define sc1(a) scanf("%lld",&a)
#define sc3(a,b,c) scanf("lld%lld",&a,&b,&c)
#define sc2(a,b) scanf("lld",&a,&b)
#define scar(arr,n) for(int index=0;index<n;index++)sc1(arr[index]);

///------------Vector------------///

#define vs vector<string>
#define vll vector<long long int >
#define vc vector<char>
#define vpll vector<pair<long long,long long> >
#define vvll vector<vector<long long>>
#define up(v,x) upper_bound(v.begin(),v.end(),x)-v.begin()
#define low(v,x) lower_bound(v.begin(),v.end(),x)-v.begin()
#define all(a) (a).begin(),(a).end()

///-------------LOOP--------------///

#define foreach(i,a) for(__typeof((a).begin()) i = (a).begin(); i != (a).end(); ++i)
#define cases ll t,ti=0;cin>>t;while((ti++)!=t)
#define fr(a,n) for(long long i = (a); i < (n); i++)
#define fri(a,n) for(long long i = (a); i <= (n); i++)

///------------limite------------///
#define eps 1e-13
//#define mod 1000000007LL
#define PI acos(-1)
#define INF 1000000011

///------------PAIR------------///

#define pii pair<int, int>
#define pll pair<long long, long long>
#define pil pair<int, long long>
#define pli pair<long long, int>
#define pcc pair<char, char>
#define pdd pair<double, double>
#define mk make_pair
#define ff first
#define ss second

///------------Extra------------///

#define clc clock_t time_req=clock()
#define pclc cout<<setprecision(10)<<(float)time_req/CLOCKS_PER_SEC
#define ll long long int
#define nl printf("\n")
#define qll queue<long long int >
#define mll map<long long int , long long int>
#define pb(x) push_back(x)
#define gtl(x) getline(cin, (x))
#define flsh fflush(stdout)
#define sws ios_base::sync_with_stdio(false); cin.tie(0)
#define mst(x) memset(x,0,sizeof(x))
#define Log(x,a) (log(a)/log(x))
#define PNY(f,a) printf((f==a)?"NO\n":"YES\n");
#define PYN(f,a) printf((f==a)?"YES\n":"NO\n");
bool CMP(int a, int b) { return a>b; }
ll p=1e9+7;
ll power2(ll n)
{
    ll res=1;
    for(ll i=1;i<=n;i++)
        res*=2;
    return res;
}
ll power(ll x, ll y)
{
    ll res = 1;     // Initialize result

    x = x % p; // Update x if it is more than or
                // equal to p

    if (x == 0) return 0; // In case x is divisible by p;

    while (y > 0)
    {
        // If y is odd, multiply x with result
        if (y & 1)
            res = (res*x) % p;

        // y must be even now
        y = y>>1; // y = y/2
        x = (x*x) % p;
    }
    return res;
}
ll cnt1=0,u,cnt=0,n;
vector<vector<ll> >adj(200010);
//vector<pair<ll,ll> >adj[200010];
vector<ll>wt(200010);
ll visi[310068],vis[300100],last1[10000];
vector<ll> viso;
bool ok=false;
ll m,ans=0;
void dfs(ll k)
{
    vis[k]=1;
    for(auto it=adj[k].begin();it!=adj[k].end();it++)
    {
        if(vis[*it]==0)
            dfs(*it);
    }
}
/*void dfs(ll k,ll parent)
{
  if(vis[k]!=1){
    vis[k]=1;
    if(a[k]==1)
      {
        a[k]=parent+1;
      }
    //cout<<1<<endl;
    if(a[k]<=m)
    {
         if(adj[k].size()==1&&k!=1)
          ans++;
          else
          {
            for(ll i=0;i<adj[k].size();i++)
                dfs(adj[k][i],a[k]);
          }
    }


  }

    //cout<<4<<endl;
}
*/

/*vector<ll> bfs(const vector<vector<ll> >& adj,ll s)
{
    ll n=adj.size();
    vector<ll>dis(n,1000'000'000);
    queue<ll>q;
    dis[s]=0;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        for(ll v: adj[u])
        {
            if(dis[v]>dis[u]+1)
            {
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
    return move(dis);
}*/
#define PI 3.14159265
 ll dp[200010];
bool mycompare(string s,string t)
{
    string x=s+t;
    string y=t+s;
    if(x>y)
        return 1;
    else
        return 0;
}


ll maxi=1e7;
set<ll>w;

pair<ll, ll> rotate(ll x, ll y, ll a, ll b, ll t)
{
    ll i;
  for (i = 0; i < t; i++)
  {
    ll p = a + b - y, q = x + b - a;
    x = p, y = q;
  }

  pair<ll, ll> P = make_pair(x, y);
  return P;
}

ll dist(ll x1, ll y1, ll x2, ll y2)
{
  ll d = (x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1);
  return d;
}

bool check(ll x1, ll y1, ll x2, ll y2, ll x3, ll y3, ll x4, ll y4)
{
  ll d2 = dist(x1, y1, x2, y2);
  ll d3 = dist(x1, y1, x3, y3);
  ll d4 = dist(x1, y1, x4, y4);

  if (d2 == 0 | d3 == 0 || d4 == 0)
    return false;

  if (d2 == d3 && d4 == 2 * d2 && 2 * dist(x2, y2, x4, y4) == dist(x2, y2, x3, y3))
    return true;

  if (d3 == d4 && d2 == 2 * d3 && 2 * dist(x2, y2, x3, y3) == dist(x3, y3, x4, y4))
    return true;

  if (d2 == d4 && d3 == 2 * d2 && 2 * dist(x2, y2, x3, y3) == dist(x2, y2, x4, y4))
    return true;

  return false;
}
#ifdef Akshat
   #include "../../trace.h"
#else
  #define trace(args...)
#endif
//vector<ll>adj(200010);
ll a[200010];
ll tree[800090];
ll lazy[800090];

void build(ll ss,ll se,ll idx)
{
    if(ss==se)
        {
            tree[idx]=a[ss];
            return ;
        }
    ll mid=(ss+se)/2;
    build(ss,mid,2*idx);
    build(mid+1,se,2*idx+1);
    tree[idx]=min(tree[2*idx],tree[2*idx+1]);
}

void update(ll ss,ll se,ll l,ll r,ll idx,ll val)
{
    if(lazy[idx]!=0)
    {
        tree[idx]+=lazy[idx];
        if(ss!=se)
        {
            lazy[2*idx]+=lazy[idx];
            lazy[2*idx+1]+=lazy[idx];
        }
        lazy[idx]=0;
    }
    if(se<l||ss>r)
        return ;
    if(ss>=l&&se<=r)
    {
        tree[idx]+=val;
        if(ss!=se)
        {
            lazy[2*idx]+=val;
            lazy[2*idx+1]+=val;
        }
        return ;
    }
    ll mid=(ss+se)/2;
    update(ss,mid,l,r,2*idx,val);
    update(mid+1,se,l,r,2*idx+1,val);
    tree[idx]=min(tree[2*idx],tree[2*idx+1]);
}

ll query(ll ss,ll se,ll l,ll r,ll idx)
{
    if(lazy[idx]!=0)
    {
        tree[idx]+=lazy[idx];
        if(ss!=se)
        {
            lazy[2*idx]+=lazy[idx];
            lazy[2*idx+1]+=lazy[idx];
        }
        lazy[idx]=0;
    }
     if(se<l||ss>r)
        return INT_MAX;
    if(ss>=l&&se<=r)
         return tree[idx];
    ll mid=(ss+se)/2;
    return min( query(ss,mid,l,r,2*idx),query(mid+1,se,l,r,2*idx+1));
}
/*ll query(ll node,ll start,ll end,ll l,ll r)
{
    if(r<start || end<l)
      return 0;
    if(l<=start && end<=r)
        return tree[node];
    ll mid=(start+end)/2;
    ll p1=query(2*node+1,start,mid,l,r);
    ll p2=query(2*node+2,mid+1,end,l,r);
    return (p1|p2);
}*/
priority_queue<pair<ll,ll>,vector<pair<ll,ll> >,greater<pair<ll,ll> > >pq;

void path(ll x)
{
    if(x==0)
        return ;
    path(visi[x]);
    cout<<x<<" ";
}
ll sum[2000100]={0};
ll MEX(vector<ll> &cnt)
{
    for(ll i=0;i<cnt.size();i++)
        if(cnt[i]==0)
        return i;
}
int main()
{
    ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    ll n,m;
    cin>>n>>m;
    ll i,x,y;
    for(i=0;i<m;i++){
    cin>>x>>y;
    adj[x].push_back(y);
    adj[y].push_back(x);
    }
    ll ans=0;
    for(i=1;i<=n;i++)
    {
        if(vis[i]==0)
        {
            dfs(i);
            ans++;
        }
    }
    cout<<ans-1<<endl;

}





Measured memory_bytes: 15088