题目中给出的是骑士中矛盾关系,可以转换一下,得到原图的补图.然后观察题目中的条件,即选择的骑士数是奇数,并且相邻之间不矛盾.对应到现在的补图上,即寻找一个奇环,使得环的大小大于等于3.也就是说,只要一个骑士能够出现在一个符合条件的奇环中那么这个骑士便是合法.
首先用Tarjan将点双连通分量全部求出,对于一个点双连通分量,可以利用交替染色的方法判断是否存在奇环,如果存在一个奇环那么这个点双连通分量中的所有点都满足要求.
证明:假设一个点双连通分量重存在一个奇环,剩下的部分是一个偶环,那么根据点双连通分量的性质,那么就可以并成一个大的奇环.如果剩下的部分是一个奇环,那么两个奇环都可以满足要求.然后类推下去,即可得到,一个点双连通分量中存在一个奇环则满足要求.
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=1005;
int n,m,dcnt,top;
int dfn[MAXN],low[MAXN],vis[MAXN];
int ban[MAXN][MAXN],co[MAXN];
int head[MAXN],ecnt;
struct edge{
int v,nxt;
}E[MAXN*MAXN*2];
struct node{
int u,v,tag;
node(){}
node(int _u,int _v,int _tag):u(_u),v(_v),tag(_tag){}
}sta[MAXN*2];
void addedge(int u,int v){
E[++ecnt].v=v,E[ecnt].nxt=head[u];
head[u]=ecnt;
}
void Tarjan(int u,int fa=0){
dfn[u]=low[u]=++dcnt;
for(int i=head[u];i;i=E[i].nxt){
int v=E[i].v;
if(!dfn[v]){
int pre=top;
sta[++top]=node(u,v,0);
co[v]=co[u]^1;
Tarjan(v,u);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u]){
int r=top,flag=0;
while(top!=pre)if(sta[top--].tag)flag=1;
while(r!=pre){
vis[sta[r].u]|=flag;
vis[sta[r].v]|=flag;
r--;
}
}
}
else if(v!=fa){
low[u]=min(low[u],dfn[v]);
if(co[u]==co[v]){
vis[u]=vis[v]=1;
if(dfn[u]>dfn[v])
sta[++top]=node(u,v,1);
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)&&(n||m)){
ecnt=dcnt=top=0;
for(int i=1;i<=n;i++){
head[i]=vis[i]=dfn[i]=low[i]=0;
for(int j=1;j<=n;j++) ban[i][j]=0;
}
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
ban[x][y]=ban[y][x]=1;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(!ban[i][j]&&i!=j) addedge(i,j);
for(int i=1;i<=n;i++)
if(!dfn[i]){
top=dcnt=0;
co[i]=0;
Tarjan(i);
}
int ans=0;
for(int i=1;i<=n;i++)
if(!vis[i]) ans++;
printf("%d\n",ans);
}
}