题意:亚瑟王要在圆桌上召开骑士会议,为了不引发骑士之间的冲突,并且能够让会议的议题有令人满意的结果,每次开会前都必须对出席会议的骑士有 如下要求:1:相互憎恨的两个骑士不能坐在直接相邻的2个位置;2:出席会议的骑士数必须是奇数,这是为了让投票表决议题时都能有结果。
现在给定准备去开会的骑士数n,再给出m对憎恨关系(表示某2个骑士之间是互相憎恨的),问有多少骑士不管跟哪些骑士都无法组成圆桌会议?
思路:没有矛盾的骑士之间建边,能组成圆桌会议的肯定形成一个环,并且环的点数为奇数。可以用Tarjan求出点双联通分量,判断每个联通分量是否存在 奇环,如果存在奇环的话,该联通分量的所有节点都可以参加会议。一个图是二分图是不存在奇环的充要条件,所以只需要判断该联通分量是否是二分图 即可。
#include<stdio.h>
#include<stack>
#include<math.h>
#include<string.h>
const int N=1010;
using namespace std;
int cnt[N],low[N],dfs[N],head[N],num,ans,idx,first[N],color[N],flag,n,eenum;
bool map[N][N],vis[N];
struct edge
{
int st,ed,next;
}e[N*N],ee[N*N];
void addedge(int x,int y)
{
e[num].st=x;e[num].ed=y;e[num].next=head[x];head[x]=num++;
e[num].st=y;e[num].ed=x;e[num].next=head[y];head[y]=num++;
}
void Addedge(int x,int y)
{
ee[eenum].st=x;ee[eenum].ed=y;ee[eenum].next=first[x];first[x]=eenum++;
ee[eenum].st=y;ee[eenum].ed=x;ee[eenum].next=first[y];first[y]=eenum++;
}
bool Judge(int u,int cor)//判断二分图
{
color[u]=cor;
int i,v;
for(i=first[u];i!=-1;i=ee[i].next)
{
v=ee[i].ed;
if(color[v]==-1)
{
return Judge(v,cor^1);
}
else if(color[v]==color[u])return true;//不是二分图
}
return false;
}
stack<int>Q;
void Tarjan(int u,int id)
{
int v,i,temp,j;
dfs[u]=low[u]=idx++;
for(i=head[u];i!=-1;i=e[i].next)
{
v=e[i].ed;
if(i==(id^1))continue;
if(dfs[v]==-1)
{
Q.push(i);
Tarjan(v,i);
low[u]=low[u]>low[v]?low[v]:low[u];
if(dfs[u]<=low[v])//u为割点
{
memset(first,-1,sizeof(first));
memset(color,-1,sizeof(color));
eenum=0;
do
{
temp=Q.top();
Q.pop();
Addedge(e[temp].st,e[temp].ed);
}while(temp!=i);//一个双联通分量的所有边
if(Judge(u,0))//如果不是二分图该联通分量里所有点都可以参加会议
{
for(j=0;j<eenum;j+=2)
vis[ee[j].st]=vis[ee[j].ed]=true;
}
}
}
else if(low[u]>dfs[v])
{
Q.push(i);
low[u]=dfs[v];
}
}
}
int main()
{
int m,x,y,i,j,sum,Case=0;
while(scanf("%d%d",&n,&m)!=-1&&n+m)
{
memset(head,-1,sizeof(head));
memset(map,false,sizeof(map));
num=0;
for(i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
map[x][y]=map[y][x]=true;
}
for(i=1;i<=n;i++)
{
for(j=i+1;j<=n;j++)
if(map[i][j]==false)
addedge(i,j);
}
memset(dfs,-1,sizeof(dfs));
memset(vis,false,sizeof(vis));
ans=idx=0;sum=0;
for(i=1;i<=n;i++)//图可能不连通
{
if(dfs[i]==-1)
Tarjan(i,-1);
}
for(i=1;i<=n;i++)
if(!vis[i])
sum++;
printf("%d\n",sum);
}
return 0;
}