搜索双连通分量。深度优先搜索过程中,用一个栈保存所有经过的节点,判断割点,碰到割点就标记当前栈顶的结点并退栈,直到当前结点停止并标记当前割点。标记过的结点处于同一个双连通分量。
交叉染色搜索奇圈。在一个节点大于2的双连通分量中,必定存在一个圈经过该连通分量的所有结点;如果这个圈是奇圈,则该连通分量内的所有的点都满足条件;若这个圈是偶圈,如果包含奇圈,则必定还有一个奇圈经过所有剩下的点。因此一个双连通分量中只要存在一个奇圈,那么该双联通分量内的所有的点都处于一个奇圈中,在题目中,即武士可以坐成一圈。根据这个性质,只需要在一个双联通分量内找奇圈即可判断该双联通分量是否满足条件。交叉染色法就是在dfs的过程中反复交换着用两种不同的颜色对点染色,若某次dfs中当前结点的子节点和当前结点同色,则找到奇圈。
//poj 2942 圆桌武士,边双连通
#include<stdio.h>
#include<string.h>
#include<vector>
const int maxn=1005;
using namespace std;
struct edge{
int s,t;
int next;
int vis;
}edge[maxn*maxn*2];
int head[maxn];
int E=0;
void add(int s,int t)
{
edge[E].s=s;
edge[E].t=t;
edge[E].vis=0;
edge[E].next=head[s];
head[s]=E++;
}
bool map[maxn][maxn];
int Btype,Time,tot;
int dfn[maxn],low[maxn],Belong[maxn],odd[maxn];
bool mark[maxn];
int st[maxn*maxn],top,col[maxn];
int n,m;
bool find(int s)
{
int t,i;
for(i=head[s];i!=-1;i=edge[i].next)
{
t=edge[i].t;
if(mark[t])
{
if(col[t]==-1)
{
col[t]=!col[s];
return find(t);
}
else if(col[t]==col[s]) return 1;
}
}
return 0;
}
void color(int s)
{
int i;
memset(mark,0,sizeof(mark));
do{
i=st[top--];
mark[edge[i].s]=1;
mark[edge[i].t]=1;
}while(edge[i].s!=s);
memset(col,-1,sizeof(col));
col[s]=0;
if(find(s))
{
for(i=1;i<=n;i++)
{
if(mark[i]) odd[i]=1;
}
}
}
inline int min(int a,int b){return a<b?a:b;}
void dfs(int s)
{
int i,t;
dfn[s]=low[s]=++Time;
for(i=head[s];i!=-1;i=edge[i].next)
{
if(edge[i].vis) continue;
edge[i].vis=edge[i^1].vis=1;
t=edge[i].t;
st[++top]=i;
if(!dfn[t])
{
dfs(t);
low[s]=min(low[s],low[t]);
if(low[t]>=dfn[s]) color(s);
}
else low[s]=min(low[s],dfn[t]);
}
}
inline void SCC()
{
int i;
Time=0;top=0;
memset(dfn,0,sizeof(dfn));
memset(odd,0,sizeof(odd));
for(i=1;i<=n;i++) if(!dfn[i])
dfs(i);
}
inline int solve()
{
int res=0,i;
SCC();
for(i=1;i<=n;i++)
if(!odd[i])
res++;
return res;
}
void read_data()
{
int i,j,a,b;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
map[i][j]=1;
for(i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
map[a][b]=map[b][a]=0;
}
memset(head,-1,sizeof(head));
E=0;
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
{
if(map[i][j])
{
add(i,j);
add(j,i);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m),n||m)
{
read_data();
printf("%d\n",solve());
}
return 0;
}