#include<iostream>
#include<cstdio>

using namespace std;

const int MAX=1000;

int father[MAX];
int height[MAX];

void Initial(int n){
    for(int i=0;i<n;i++){                //初始化,每个节点父节点是自己,高度为0
        father[i]=i;                        //模拟初始时每个城镇都是孤立的
        height[i]=0;
    }
}

int Find(int x){                            //查找根结点
    if(x!=father[x])
        father[x]=Find(father[x]);            //一直循环找到x=father[x],根结点
    return father[x];
}

void Union(int x ,int y){
    x=Find(x);
    y=Find(y);
    if(x!=y){                            //矮树作为高树的子树
        if(height[x]<height[y])
            father[x]=y;
        else if(height[x]>height[y])
            father[y]=x;
        else{                            //遇到相同情况,让y加入到x中去
            father[y]=x;
            height[x]++;
        }
    }
    return ;
}

int main(){
    int n,m;
    while(scanf("%d",&n)!=EOF){
        if(n==0)
            break;
        scanf("%d",&m);
        Initial(n);
        while(m--){
            int x,y;
            scanf("%d",&x);
            scanf("%d",&y);
            Union(x,y);                    //读入已经建成的道路,联通道路==合并集合
        }
        int answer=-1;
        for(int i=0;i<=n;i++){            //最后计算所有结点被保存到几个集合中即可
            if(Find(i)==i)                //一个点在几个图中,即还需要最少建立几条路联通
                answer++;
        }
        printf("%d\n",answer);
    }
    return 0;
}