王桂平的图论书上把这题错误地归类为边双联通分量,于是WA到生活不能自理。主要区别在于这样的图:
显然按照每个点经过一次的环来算的话,这个图并不能构成环,所以每个点经过一次的环应该包含于点双联通分量内部。
而每条边经过一次的环包含于边双联通分量内部。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct edge{
int to,next;
}e[2000003];
bool used[2000003];
bool vis[1003];
int head[1003];
int cnt,tmpdfn;
int dfn[1003];
int low[1003];
int color[1003];
int bcc[1003];
int stk[1003];
bool odd[1003];
bool g[1003][1003];
int ans,n,m,bcc_cnt,top;
bool flag;
void add(int u,int v){
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void init(){
cnt=tmpdfn=ans=bcc_cnt=0;
memset(g,false,sizeof(g));
memset(vis,false,sizeof(vis));
memset(used,false,sizeof(used));
memset(head,-1,sizeof(head));
memset(bcc,0,sizeof(bcc));
memset(odd,false,sizeof(odd));
}
bool draw(int u,int c){
color[u]=c;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(bcc[v]!=bcc_cnt)continue;
if(color[v]==-1){
if(!draw(v,c^1))return false;
}
else if(color[v]==color[u])return false;
}
return true;
}
void dfs(int u){
vis[u]=true;
dfn[u]=++tmpdfn;
low[u]=dfn[u];
stk[++top]=u;
for(int i=head[u];~i;i=e[i].next){
if(used[i])continue;
used[i]=used[i^1]=true;
int v=e[i].to;
if(vis[v]){
low[u]=min(low[u],dfn[v]);
}
else {
dfs(v);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
++bcc_cnt;
while(1){
int x=stk[top--];
bcc[x]=bcc_cnt;
if(x==v)break;
}
bcc[u]=bcc_cnt;
memset(color,-1,sizeof(color));
if(!draw(u,0)){
for(int j=1;j<=n;j++)if(bcc[j]==bcc_cnt)odd[j]=true;
}
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0)break;
init();
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
g[u][v]=g[v][u]=true;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(!g[i][j]){
add(i,j);
add(j,i);
}
}
}
for(int i=1;i<=n;i++){
if(!vis[i])dfs(i);
}
for(int i=1;i<=n;i++){
if(!odd[i])ans++;
}
printf("%d\n",ans);
}
}