题意:一些骑士,他们有些人之间有矛盾,现在要求选出一些骑士围成一圈,圈要满足如下条件:1.人数大于1。2.总人数为奇数。3.有仇恨的骑士不能挨着坐。问有几个骑士不能和任何人形成任何的圆圈。
有很多需要注意的点
①他给我们相互憎恨的骑士线段,我们先变成补图,也就是相连的是可以在一起坐的,不相连的是不能在一起坐的。也就是说我们
要从相连的当中找。 (先求补图)
②他让我们求的是任何搭配都不行的骑士的数量,就是说完全不能开会的,我们要遍历各种情况。
③tarjan求双联通,每求出一个双联通区,我们要先判断是否为奇数个,利用二分染色法判断判断是不是奇数个。(题目要求为奇数个人)。如果是
记录所有的成员,这些成员都不用踢出去,我们再找继续找其他的强连通图即可。
基本思路:
①我们一般做这种题,都会往tarjan上靠,对于这道题,如果我们想用tarjan来做,必然是说明部分点可以合并,也就是相互信任的点可以合并。而题目给的
是相互憎恨的,所以我们要求补图
②对于判断一个图是否为奇圈,就是用染色法判断即可。
③什么时候判断,也就是每次找出一个强连通是就要判断一次,因为这样省空间省时间。
④题目一定要读懂,是任何一个会议都不能参加的。人数要>3的。
#include <iostream>
#include <queue>
#include <string.h>
#include <stdio.h>
using namespace std;
const int maxn=1005;
const int maxm=1000005;
struct Edge
{
int to,next;
} edge[maxm];
int head[maxn],tot;
int g[maxn][maxn];
int low[maxn],dfn[maxn],Stack[maxn],belong[maxn];
int Index,top;
int block;
bool Instack[maxn];
bool can[maxn];
bool ok[maxn];
int tmp[maxn];
int cc;
int color [maxn];
void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].next=head[u];
head[u]=tot++;
}
bool dfs(int u,int col)
{
color[u]=col;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
if(!ok[v])
continue;
if(color[v]!=-1)
{
if(color[v]==col)
return false;
continue;
}
if(!dfs(v,!col))
return false;
}
return true;
}
void tarjan(int u,int pre)
{
int v;
low[u]=dfn[u]=++Index;
Stack[top++]=u;
Instack[u]=true;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
v=edge[i].to;
if(v==pre)
continue;
if(!dfn[v])
{
tarjan(v,u);
if(low[u]>low[v])
low[u]=low[v];
if(low[v]>=dfn[u])
{
block++;
int vn;
cc=0;
memset(ok,false,sizeof(ok));
do
{
vn=Stack[--top];
belong[vn]=block;
Instack[vn]=false;
ok[vn]=true;
tmp[cc++]=vn;
}
while(v!=vn);
ok[u]=1;
memset(color,-1,sizeof(color));
if(!dfs(u,0))
{
can[u]=true;
while(cc--)
can[tmp[cc]]=true;
}
}
}
else if(low[u]>dfn[v])
low[u]=dfn[v];
}
}
void init()
{
tot=0;
memset(head,-1,sizeof(head));
memset(g,0,sizeof(g));
memset(low,0,sizeof(low));
memset(can,0,sizeof(can));
memset(dfn,0,sizeof(dfn));
memset(Instack,false,sizeof(Instack));
Index=block=top=0;
}
int main()
{
int n,m,k1,k2;
while(cin>>n>>m)
{
if(n==0&&m==0)
break;
init();
for(int i=1; i<=m; i++)
{
cin>>k1>>k2;
g[k1][k2]=g[k2][k1]=1;
}
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
if(i!=j&&!g[i][j])
{
addedge(i,j);
}
}
for(int i=1; i<=n; i++)
if(!dfn[i])
tarjan(i,-1);
int ans=n;
for(int i=1; i<=n; i++)
if(can[i])
ans--;
cout<<ans<<endl;
}
return 0;
}