首先我们建出补图,那么就是求这样的点的个数:不在任何一个>=3的奇环上。
我们搞出点双,如果点x,y不在一个点双内,那么他俩一定不在一个环上。
所以我们对每个点双分别讨论。
这里有一个结论:如果一个点双内存在一个奇环,那么这个点双内的每一个点都在一个奇环上。
大概口胡一下:对于一个点双,一定存在一个过所有点的简单环路。如果这个点双有奇数个点,则得证。
否则如果我们找到了一个奇环。点双内部的环与环之间一定有至少两个公共点,所以这个奇环与大环至少有两个公共点,而这两个公共点把奇环分成了奇数个点/偶数个点的两部分,我们取偶数那部分,再加上剩余的不在奇环上的点则可以构成一个奇环。
因此我们只需要对每一个bcc二分图染色,看是否存在奇环即可。注意对割点的处理qaq
复杂度
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <stack>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 1010
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,m,h[N],num,dfn[N],low[N],dfnum,col[N],h1[N],num1,a[N];
bool ok[N],mp[N][N],used[1000010];
struct edge{
int to,next;
}data[1000010<<1],data1[1000010<<1];
stack<int>qq;
stack<int>qqq;
inline void add(int x,int y){
data1[++num1].to=y;data1[num1].next=h1[x];h1[x]=num1;
data1[++num1].to=x;data1[num1].next=h1[y];h1[y]=num1;
}
bool dfs(int x){
for(int i=h1[x];i;i=data1[i].next){
int y=data1[i].to;
if(col[y]!=-1){
if(col[y]==col[x]) return 1;continue;
}col[y]=col[x]^1;if(dfs(y)) return 1;
}return 0;
}
inline void tarjan(int x){
dfn[x]=low[x]=++dfnum;qq.push(x);
for(int i=h[x];i;i=data[i].next){
int y=data[i].to;if(used[i>>1]) continue;
used[i>>1]=1;qqq.push(i>>1);
if(!dfn[y]){
tarjan(y);low[x]=min(low[x],low[y]);
if(low[y]<dfn[x]) continue;m=0;
while(1){
int z=qq.top();qq.pop();a[++m]=z;
if(z==y) break;
}a[++m]=x;
while(1){
int j=qqq.top();qqq.pop();add(data[j<<1].to,data[j<<1|1].to);
if(j==i/2) break;
}col[x]=0;if(dfs(x)) for(int i=1;i<=m;++i) ok[a[i]]=1;
for(int i=1;i<=m;++i) h1[a[i]]=0,col[a[i]]=-1;num1=0;continue;
}low[x]=min(low[x],dfn[y]);
}
}
int main(){
// freopen("a.in","r",stdin);
while(1){
n=read();m=read();if(!n&!m) break;memset(h,0,sizeof(h));num=1;memset(dfn,0,sizeof(dfn));dfnum=0;
memset(col,-1,sizeof(col));memset(ok,0,sizeof(ok));int ans=0;memset(mp,0,sizeof(mp));memset(used,0,sizeof(used));
while(m--){int x=read(),y=read();mp[x][y]=mp[y][x]=1;}
for(int x=1;x<=n;++x)
for(int y=x+1;y<=n;++y){
if(mp[x][y]) continue;
data[++num].to=y;data[num].next=h[x];h[x]=num;
data[++num].to=x;data[num].next=h[y];h[y]=num;
}
for(int i=1;i<=n;++i) if(!dfn[i]) tarjan(i),qq.pop();
for(int i=1;i<=n;++i) if(!ok[i]) ++ans;
printf("%d\n",ans);
}return 0;
}