- 建补图时注意不能向自己连边
- 割点可能属于多个点双连通分量,因此染色时需要多次清空
- 求点双连通分量时,注意需要特判“孤立点”,尽管这道题不影响
- 引理:在一个点双连通分量中,只要存在一个奇环,那就可以把任意一个点包含在一个奇环内
#include <bits/stdc++.h>
using namespace std;
vector<int>a[1005],dcc[1005];
bool b[1005][1005];
int dfn[1005],low[1005],tot,cnt,col[1005],id[1005];
stack<int>s;
bool f[1005];
bool pd;
void tarjan(int n1,int fa)
{dfn[n1]=low[n1]=++tot;s.push(n1);if(fa==0&&a[n1].size()==0){cnt++;dcc[cnt].push_back(n1);}for(int i=0;i<a[n1].size();i++){if(a[n1][i]==fa){continue;}if(!dfn[a[n1][i]]){tarjan(a[n1][i],n1);low[n1]=min(low[n1],low[a[n1][i]]);if(dfn[n1]<=low[a[n1][i]]){cnt++;while(s.top()!=a[n1][i]){dcc[cnt].push_back(s.top());s.pop();}dcc[cnt].push_back(a[n1][i]);s.pop();dcc[cnt].push_back(n1);}}else{low[n1]=min(low[n1],dfn[a[n1][i]]);}}
}
void dfs(int n1)
{if(pd==false){return;}for(int i=0;i<a[n1].size();i++){if(id[a[n1][i]]!=id[n1]){continue;}if(!col[a[n1][i]]){col[a[n1][i]]=3-col[n1];dfs(a[n1][i]);}else if(col[a[n1][i]]!=3-col[n1]){pd=false;break;}}
}
int main()
{ios::sync_with_stdio(false);cin.tie(0);int n,m;cin>>n>>m;while(!(n==0&&m==0)){for(int i=1;i<=n;i++){a[i].clear();dcc[i].clear();dfn[i]=id[i]=0;f[i]=false;for(int j=1;j<=n;j++){b[i][j]=true;}}for(int i=1;i<=m;i++){int u,v;cin>>u>>v;b[u][v]=b[v][u]=false;}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(b[i][j]&&i!=j){a[i].push_back(j);}}}tot=cnt=0;for(int i=1;i<=n;i++){if(!dfn[i]){tarjan(i,0);while(s.size()){s.pop();}}}for(int i=1;i<=cnt;i++){pd=true;col[dcc[i][0]]=1;for(int j=0;j<dcc[i].size();j++){id[dcc[i][j]]=i;col[dcc[i][j]]=0;}dfs(dcc[i][0]);if(pd==false){for(int j=0;j<dcc[i].size();j++){f[dcc[i][j]]=true;}}}cout<<n-accumulate(f+1,f+n+1,0)<<"\n";cin>>n>>m;} return 0;
}