/*
并查集:是一种树形的数据结构,用于处理一些不相交集合的合并及查询问题.
主要操作有:查找(查找该结点属于哪个集合),合并(合并两个不相交的集合).
初始化问题;最开始的时候,每一个结点都是一个独立的集合.
查找:查找其祖先结点(用递归可以进行路径压缩,即在结点在查找祖先回溯时把经过的结点都归为一个集合,即其祖先结点一样).
合并:就是将一个集合的祖先指向另一个集合的祖先.
*/
//NYoj608&&Hud1232 畅通工程.(简单的并查集).
#include<cstdio>
using namespace std;
int father[1002],M,N;
void Init()
{
for(int i=1;i<=M;i++)
father[i]=i;
}
int Find_Father(int x)
{
if(father[x]!=x)
father[x]=Find_Father(father[x]);
return father[x];//回溯的时候直接把要找的祖先付给其子孙.
}
void Union(int a,int b)
{
int x=Find_Father(a);
int y=Find_Father(b);
// printf("%d %d\n",x,y);
if(x!=y) father[x]=y;
}
int main()
{
while(scanf("%d",&M)&&M)
{
int a,b;
scanf("%d",&N);
Init();
for(int i=1;i<=N;i++)
{
scanf("%d%d",&a,&b);
Union(a,b);
for(int j=1;j<=M;j++)
printf("%d ",father[j]);
printf("\n");
}
// int D,k,l;
// scanf("%d",&D);
// for(int i=1;i<=D;i++)
// {
// scanf("%d%d",&k,&l);
// if(Find_Father(k)==Find_Father(l))
// printf("YES\n");
// else printf("NO\n");
// }
int UnionNum=0;
for(int i=1;i<=M;i++)
if(father[i]==i) UnionNum++;
printf("%d\n",UnionNum-1);
}
}