#include <cstring>
#include <iostream>
#include <set>
using namespace std;
#define _for(i, a, b) for(int i = a; i < b; i++)
const int N = 1000;
int father[N];
int ranks[N];
 //查找:findFather函数返回元素x所在集合的根结点
int findFather(int x){
    int a = x;
    while(father[x] != -1){//如果不是根结点,继续循环
        x = father[x];
    }
    //到这里,x存放的是根结点。下面把路径上的所有结点的father都改成根结点
    while(father[a] != -1){
        int z = a;//因为a要被father[a]覆盖,所以先保存a的值,以修改father[a]
        a = father[a];//a回溯父亲结点
        father[z] = x;//将原先的结点a的父亲改为根结点x
    }
    return x;
}
void Union(int a, int b){
    int faA = findFather(a);//查找a的根结点,记为faA
    int faB = findFather(b);//查找b的根结点,记为faB
    if(ranks[faA] < ranks[faB]){
        father[faA] = faB;
    }else if(ranks[faB] < ranks[faA]){
        father[faB] = faA;
    }else if(faA != faB){
        father[faA] = faB;
        ranks[faB] += 1;
    }
}
int main(){
    //初始化
    int n, m;//结点数目:n 连线数目: m
    while(~scanf("%d", &n) && n){
        scanf("%d", &m);
        _for(i, 1, n + 1) {father[i] = -1; ranks[i] = 1;}
        while(m--){
            int a, b;
            scanf("%d %d", &a, &b);
            Union(a, b);
        }
        int ans = 0;//获取当前集合数量
        _for(i, 1, n + 1){
            if(father[i] == -1)
                ans++;
        }
        printf("%d\n", ans - 1);
    }
    return 0;
}