Solution:
若两人之间无限制,则连一条无向边。
引理一:
如果两个人处于不同的点双连通分量,则两人不能同时参与一场会议。
这意味着: 我们可以单独考虑每一个点双联通分量。
引理二:
某个人能够参与会议,当且仅当它位于至少一个奇环上。
这意味着:我们只需要统计有多少个点不被任何奇环包含。
引理三:
一个点双连通分量中,若存在一个奇环,则所有的点都被至少一个奇环包含。否则所有点不被任何奇环包含。
证明如下:
对于点双中存在的一个奇环,它肯定由一部分长度为奇数,和一部分长度为偶数的路径组成。
那么,对于非环上的点,它必然至少被包含在两个环上,其中一个为奇环,一个为偶环。
证毕。
所以直接把对一个v-DCC进行dfs染色,按照二分图判定的方式来判定。
Code↓:
#include<string>
#include<cstdio>
#include<cstring>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;
IL int gi() {
char ch=getchar(); RG int x=0,w=0;
while (ch<'0'||ch>'9') {if (ch=='-') w=1;ch=getchar();}
while (ch>='0'&&ch<='9') x=x*10+(ch^48),ch=getchar();
return w?-x:x;
}
const int N=1010;
const int M=1e6+10;
int n,m,sum,top,cnt,tot,Time,a[N][N],head[N],ST[N],OK[N],dfn[N],low[N],sta[N],bel[N],col[N];
struct VER{int x,y;}In[M];
struct EDGE{int next,to;}e[M<<1];
IL void make(int x,int y) {
e[++tot]=(EDGE){head[x],y},head[x]=tot;
e[++tot]=(EDGE){head[y],x},head[y]=tot;
}
IL bool dfs(int x,int color,int id) {
RG int i,y;
col[x]=color;
for (i=head[x];i;i=e[i].next) {
y=e[i].to;
if (bel[y]!=id) continue;
if (!col[y]) {
if (dfs(y,3-color,id)) return 1;
}
else if (col[y]==color) return 1;
}
return 0;
}
void Tarjan(int x) {
RG int i,j,y,now,num=0;
dfn[x]=low[x]=++Time,sta[++top]=x;
for (i=head[x];i;i=e[i].next) {
if (!dfn[y=e[i].to]) {
Tarjan(y),low[x]=min(low[x],low[y]);
if (low[y]>=dfn[x]) {
++cnt;
do {
now=sta[top--],bel[now]=cnt,ST[++num]=now;
}while(now!=y);
bel[x]=cnt,ST[++num]=x;
if (dfs(ST[1],1,cnt))
for (j=1;j<=num;++j) OK[ST[j]]=1;
for (;num;--num) col[ST[num]]=0;
}
}
else low[x]=min(low[x],dfn[y]);
}
}
int main()
{
RG int i,j,x,y;
n=gi(),m=gi();
while(n&&m) {
for (i=1;i<=m;++i) {
x=In[i].x=gi(),y=In[i].y=gi();
a[x][y]=a[y][x]=1;
}
memset(&e,0,sizeof(e));
memset(head,0,sizeof(head));
for (i=1,tot=0;i<=n;++i)
for (j=i+1;j<=n;++j)
if (!a[i][j]) make(i,j);
else a[i][j]=a[j][i]=0;
sum=top=cnt=Time=0;
memset(OK,0,sizeof(OK));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(bel,0,sizeof(bel));
for (i=1;i<=n;++i)
if (!dfn[i]) Tarjan(i);
for (i=1;i<=n;++i) sum+=OK[i];
printf("%d
",n-sum);
n=gi(),m=gi();
}
return 0;
}