/*
poj2942 双连通分量
Author: lcy
Time: 2017-11-8
白书例题
跑一遍双联通分量。对于每个双联通分量,
只要其中存在一个奇环,对于任意一个骑士,
我们便可以构造一个包含他的奇环。
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
using namespace std;
#define ll long long
#define fr(i,a,b) for(int i=a;i<=b;i++)
#define frr(i,a,b) for(int i=a;i>=b;i--)
#define ms(a,b) memset(a,b,sizeof(a))
#define scfd(a) scanf("%d",a)
#define scflf(a) scanf("%lf",a)
#define scfs(a) scanf("%s",a)
#define ptfd(a) printf("%d\n",a)
#define ptfs(a) printf("%s\n",a)
#define showd(a,b) printf(a"=%d\n",b)
#define showlf(a,b) printf(a"=%lf\n",b)
#define shows(a,b) printf(a"=%s\n",b)
#define mmcp(a,b) memcpy(a,b,sizeof(b))
#define pb(a) push_back(a)
const int MAXN=1005;
struct edge{
int f,t;
};
vector<edge>e;
vector<int>g[MAXN];
vector<int>bcc[MAXN];
stack<edge>s;//栈存边
//如果存点,由于dfs每个点只入栈一次,而割顶属于可能属于多个bcc,弹栈后使得后面的bcc少了该点。
//由于两个bcc至多有一个公共点且该点为割顶,所以没有公共边。
//dfs时,每个边入栈一次,而每个边又至多属于一个bcc。故存边更加方便。
int tot,p[MAXN],bidx[MAXN],bcnt;//bcccnt从1开始,0代表没有进入任何bcc
bool iscut[MAXN];//同时求出割顶
inline void add_edge(int f,int t){
//printf("build %d to %d\n",f,t);
e.push_back((edge){f,t});
e.push_back((edge){t,f});
g[f].push_back(e.size()-2);
g[t].push_back(e.size()-1);
}
int dfs(int x,int fa){//返回最low
//printf("now move to %d\n",x);
int lowx,sz,cnt=0;
lowx=p[x]=++tot;//从1开始,0代表没有访问
sz=g[x].size();
fr(i,0,sz-1){
edge ne=e[g[x][i]];
if(!p[ne.t]){
s.push(ne);
int lowt=dfs(ne.t,x);
lowx=min(lowx,lowt);
if(lowt>=p[x]){//x是割顶,将子树及x加入同一双联通分量
iscut[x]=true;
cnt++;
bcnt++;bcc[bcnt].clear();//多组数据,随用随清
//puts("Another bcc");
for(;;){
edge t=s.top();s.pop();
if(bidx[t.f]!=bcnt){//防止子树中有的点进入bcc多次,同时处理割顶
//printf("%d ",t.f);
bidx[t.f]=bcnt;
bcc[bcnt].push_back(t.f);
}
if(bidx[t.t]!=bcnt){
//printf("%d ",t.t);
bidx[t.t]=bcnt;
bcc[bcnt].push_back(t.t);
}
if(t.f==x&&t.t==ne.t)break;
}
//puts("\nbcc");
}
}
else if(p[ne.t]<p[x]&&ne.t!=fa){
s.push(ne);
lowx=min(lowx,p[ne.t]);//用从x出发反向边更新
}
}
if(cnt==1&&fa==-1)iscut[x]=false;//树根至少需要两个子树才能成为割顶
return lowx;
}
int n,m,col[MAXN];
bool hate[MAXN][MAXN],ok[MAXN];
inline void init(){
tot=bcnt=0;
e.clear();
fr(i,0,MAXN-1)g[i].clear();
while(!s.empty())s.pop();
ms(p,0);
ms(iscut,false);
ms(bidx,0);
ms(hate,false);
ms(ok,false);
ms(col,0);
}
inline void find_bcc(){
fr(i,1,n)if(!p[i])dfs(i,-1);
}
bool chk(int x,int b){
int sz=g[x].size();
int nc=((col[x]-1)^1)+1;
//printf("x=%d,nc=%d\n",x,nc);
fr(i,0,sz-1){
edge ne=e[g[x][i]];
if(bidx[ne.t]!=b)continue;
if(!col[ne.t]){
col[ne.t]=nc;
bool t=chk(ne.t,b);
if(!t)return t;
}
else if(col[ne.t]!=nc)
return false;
}
return true;
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(!n&&!m)break;
init();
fr(i,1,m){
int a,b;
scanf("%d%d",&a,&b);
hate[a][b]=hate[b][a]=true;
}
fr(i,1,n)
fr(j,i+1,n)
if(!hate[i][j])
add_edge(i,j);
find_bcc();
int ans=0;
fr(i,1,bcnt){
int sz=bcc[i].size();
fr(j,0,sz-1)bidx[bcc[i][j]]=i;//把割顶标回来
col[bcc[i][0]]=1;
if(!chk(bcc[i][0],i))//存在奇圈
fr(j,0,sz-1)ok[bcc[i][j]]=true;
fr(j,0,sz-1)col[bcc[i][j]]=0;//还原颜色标记,割顶
}
fr(i,1,n)if(ok[i])ans++;
ans=n-ans;
ptfd(ans);
}
return 0;
}