#dt = {} for i in x: dt[i] = dt.get(i,0)+1

import sys;input = sys.stdin.readline

inp,ip = lambda :int(eval(input())),lambda :[int(w) for w in input().split()]

"""

n,k = ip()

x = [inp() for i in range(n)]

"""

import sys

sys.setrecursionlimit(10**6)

def dfs(u):

    global vis,graph

    vis.add(u)

    for i in graph[u]:

        if i not in vis:

            dfs(i)





n,m = ip()

graph = {i:[] for i in range(1,n+1)}

for i in range(m):

    a,b = ip()

    graph[a].append(b)

    graph[b].append(a)

vis = set()

ct = 0

for i in range(1,n+1):

    if i not in vis:

        dfs(i)

        ct += 1

print((ct-1))
#dt = {} for i in x: dt[i] = dt.get(i,0)+1

import sys;input = sys.stdin.readline

#import io,os; input = io.BytesIO(os.read(0,os.fstat(0).st_size)).readline #for pypy

inp,ip = lambda :int(eval(input())),lambda :[int(w) for w in input().split()]



class DisjSet: 

    def __init__(self,n): 

        self.rank = [1]*n 

        self.parent = [i for i in range(n)] 



    def find(self,x): 

        if self.parent[x] != x:

            self.parent[x] = self.find(self.parent[x]) 

        return self.parent[x]



    def Union(self,x,y):

        xset = self.find(x) 

        yset = self.find(y)

        if xset == yset: return



        if self.rank[xset] < self.rank[yset]: 

            self.parent[xset] = yset 

        elif self.rank[xset] > self.rank[yset]: 

            self.parent[yset] = xset 

        else: 

            self.parent[yset] = xset 

            self.rank[xset] += 1



n,m = ip()

obj = DisjSet(n)

for i in range(m):

    a,b = ip()

    obj.Union(a-1,b-1)

dt = {}

for i in range(n):

    p = obj.find(i)

    dt[p] = dt.get(p,0)+1

print((len(list(dt.keys()))-1))

    

# dt = {} for i in x: dt[i] = dt.get(i,0)+1
import sys

input = sys.stdin.readline
inp, ip = lambda: int(eval(input())), lambda: [int(w) for w in input().split()]
"""
n,k = ip()
x = [inp() for i in range(n)]
"""
import sys

sys.setrecursionlimit(10**6)


def dfs(u):
    global vis, graph
    vis.add(u)
    for i in graph[u]:
        if i not in vis:
            dfs(i)


n, m = ip()
graph = {i: [] for i in range(1, n + 1)}
for i in range(m):
    a, b = ip()
    graph[a].append(b)
    graph[b].append(a)
vis = set()
ct = 0
for i in range(1, n + 1):
    if i not in vis:
        dfs(i)
        ct += 1
print((ct - 1))

# dt = {} for i in x: dt[i] = dt.get(i,0)+1
import sys

input = sys.stdin.readline
# import io,os; input = io.BytesIO(os.read(0,os.fstat(0).st_size)).readline #for pypy
inp, ip = lambda: int(eval(input())), lambda: [int(w) for w in input().split()]


class DisjSet:
    def __init__(self, n):
        self.rank = [1] * n
        self.parent = [i for i in range(n)]

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])
        return self.parent[x]

    def Union(self, x, y):
        xset = self.find(x)
        yset = self.find(y)
        if xset == yset:
            return
        if self.rank[xset] < self.rank[yset]:
            self.parent[xset] = yset
        elif self.rank[xset] > self.rank[yset]:
            self.parent[yset] = xset
        else:
            self.parent[yset] = xset
            self.rank[xset] += 1


n, m = ip()
obj = DisjSet(n)
for i in range(m):
    a, b = ip()
    obj.Union(a - 1, b - 1)
dt = {}
for i in range(n):
    p = obj.find(i)
    dt[p] = dt.get(p, 0) + 1
print((len(list(dt.keys())) - 1))

+# import io,os; input = io.BytesIO(os.read(0,os.fstat(0).st_size)).readline #for pypy -""" -n,k = ip() -x = [inp() for i in range(n)] -""" -import sys - -sys.setrecursionlimit(10**6) -def dfs(u): -    global vis, graph -    vis.add(u) -    for i in graph[u]: -        if i not in vis: -            dfs(i) +class DisjSet: +    def __init__(self, n): +        self.rank = [1] * n +        self.parent = [i for i in range(n)] + +    def find(self, x): +        if self.parent[x] != x: +            self.parent[x] = self.find(self.parent[x]) +        return self.parent[x] + +    def Union(self, x, y): +        xset = self.find(x) +        yset = self.find(y) +        if xset == yset: +            return +        if self.rank[xset] < self.rank[yset]: +            self.parent[xset] = yset +        elif self.rank[xset] > self.rank[yset]: +            self.parent[yset] = xset +        else: +            self.parent[yset] = xset +            self.rank[xset] += 1 -graph = {i: [] for i in range(1, n + 1)} +obj = DisjSet(n) -    graph[a].append(b) -    graph[b].append(a) -vis = set() -ct = 0 -for i in range(1, n + 1): -    if i not in vis: -        dfs(i) -        ct += 1 -print((ct - 1)) +    obj.Union(a - 1, b - 1) +dt = {} +for i in range(n): +    p = obj.find(i) +    dt[p] = dt.get(p, 0) + 1 +print((len(list(dt.keys())) - 1))