#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <unordered_set>
#include <unordered_map>
#include <queue>
#include <ctime>
#include <cassert>
#include <complex>
#include <string>
#include <cstring>
#include <chrono>
#include <random>
#include <bitset>
#include <ext/pb_ds/assoc_container.hpp>
#include <iomanip> 
#include <thread>
#define endl "\n"
using namespace std;
#define ios ios_base::sync_with_stdio(false);
#define lll __int128_t
#define ll long long int
#define XOX
#define FOR(i,a,b) for(ll i=a;i<(ll)b;i++)
#define FORr(i,a,b) for(ll i =a;i>=(ll)b;i--)
#define rep(i,n) FOR(i,0,n)
#define rep1(i,n) FOR(i,1,n)
#define print(arr)  for(auto a: arr) cout << a<< " "; cout << endl;
#define case(i) cout << "Case " << i << ": ";
#define in(a) ll a = read();
#define inp(arr,n) vector<ll>arr(n); for(auto &a: arr) a = read(); 
#define pb emplace_back
#define all(a) a.begin(), a.end()
#define mp make_pair
#define f first
#define s second
#define mod 998244353
#define pll pair<ll, ll>
#define set_bit(x, idx) x = x|1LL<<idx
#define toggle_bit(x, idx) x = x^(1LL<<idx)
#define check_bit(x, idx) min(x&(1LL<<idx),1LL)
inline ll read()
{
    long long int x=0; static long long int p; p=1; static char c; c=getchar();
    while (!isdigit(c)) { if (c=='-') p=-1; c=getchar(); }
    while ( isdigit(c)) { x=(x<<1)+(x<<3)+(c-48); c=getchar(); }
    x*=p;
    return x;
}
template<typename T> ostream& operator<<(ostream &os, const multiset<T> &v) { os << '{'; string sep; for (const auto &x : v) os << sep << x, sep = ", "; return os << '}'; }
template<typename T> ostream& operator<<(ostream &os, const set<T> &v) { os << '{'; string sep; for (const auto &x : v) os << sep << x, sep = ", "; return os << '}'; }
template<typename T> ostream& operator<<(ostream &os, const vector<T> &v) { os << '{'; string sep; for (const auto &x : v) os << sep << x, sep = ", "; return os << '}'; }
template<typename T, size_t size> ostream& operator<<(ostream &os, const array<T, size> &arr) { os << '{'; string sep; for (const auto &x : arr) os << sep << x, sep = ", "; return os << '}'; }
template<typename A, typename B> ostream& operator<<(ostream &os, const pair<A, B> &p) { return os << '(' << p.first << ", " << p.second << ')'; }
 
void dbg_out() { cerr << endl; }
template<typename Head, typename... Tail> void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); }

//#define DEBUG
#ifdef DEBUG
#define dbg(...) cerr << __LINE__ << " : " ;cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__)
#define ok cerr << __LINE__ << " is done " << endl;
#else
#define dbg(...)
#define ok 
#endif
void solve(int pk);
vector<ll>adj[100005];
vector<ll>vis(100005);
void dfs(ll node){
    vis[node] = 1;
    for(auto A: adj[node]){
        if(!vis[A])
        dfs(A);
    }
}

int main()
{
 //freopen("in", "r", stdin);
   ll nn = 1;
  // nn= read();
  //  ios
 //  cin >> nn; 
    rep(i, nn) solve(i);
}
void solve(int tt)
{
   in(n) in(m)
   rep(i, m){
       in(a) in(b)
        adj[a].pb(b);
        adj[b].pb(a);
   }
   ll ans = 0;
   rep1(i, n+1){
       if(!vis[i]){
           dfs(i); ans++;
       }
   }
   ans --;
   cout << ans << endl;

   
}
 

Measured memory_bytes: 10532