poj 2942 (点双联通+判断二分图)

题意:亚瑟王要在圆桌上召开骑士会议,为了不引发骑士之间的冲突,并且能够让会议的议题有令人满意的结果,每次开会前都必须对出席会议的骑士有   如下要求: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;
}

点赞