题目链接:http://poj.org/problem?id=2942

题意:n个骑士要举行圆桌会议,但是有些骑士相互仇视,必须满足以下两个条件才能举行:

(1)任何两个互相仇视的骑士不能相邻,每个骑士有两个相邻的骑士(即如果只有一个骑士,则不能举行会议)

(2)圆桌会议坐下的骑士数量必须为奇数个

有一张名单列出m个相互仇视的骑士,如果遵守以上两个规则,可能是某些骑士不可能被安排坐下,一种情况是一个骑士仇视所有其他的骑士。如果一个骑士不可能被安排坐下,则将他从骑士名单中剔除,问有多少个骑士会被剔除掉。

1<=n<=100,1<=m<=1000000

分析:题目上好像是说所有不被剔除的骑士都要参加圆桌会议,我严重怀疑这道题的题意是不是不明确,要不然就是poj的数据有问题。所以我将这题的题意理解为:不一定要所有不被剔除的骑士都要参加圆桌会议,只需其中的一部分就行了,这样有些数据就能解释为什么了。

将骑士看成顶点,不互相仇视的骑士连边,建无向图,即建反图。构造无向图之后,先按要求(1),将所有能坐在一起的骑士分为一组,全部骑士分为若干组,每一组在图中是一个双连通分量。注意,这里我们要求的是点双连通分量,是点双,不是边双。为什么呢?因为我们是要剔除掉骑士,而骑士就是一个顶点了,并不是剔除掉仇恨关系,所以是点双。

每一个双连通分量就是一个环了,但是这只是找到了环,而题目要求的是顶点数为奇数的环,即奇圈。

那么怎么判断奇圈呢?这里有两个定理:

(1)如果一个双连通分量中存在一个奇圈,那么该双连通分量内的所有顶点都处在某个奇圈内。

在一个双连通分量中,必定存在一个圈经过该连通分量的所有节点,如果这个圈是奇圈,则该连通分量内所有的点都满足条件;若这个圈是偶圈,如果包含奇圈,则必定有另一个奇圈经过由剩下的点或该奇圈内至少2个点及其边构成的环。

(2)一个双连通分量含有奇圈当且仅当它不是一个二分图。

直观的想,对于一个二分图,从一个点出发要回到一个点显然要经过偶数个节点,所以肯定不存在奇圈。

所以判断一个双连通分量是否含有奇圈,只需判断该双连通分量是否是二分图就行了,而判二分图可以用交叉染色法。

交叉染色法就是在DFS过程中反复交换着用两种不同的颜色对未染色过的点染色,若某次DFS中当前点的子节点和当前节点同色,则找到奇圈。

想象一下二分图就像是河的两岸有两排节点,没染色一次就过河一次,那么相同颜色的节点必定在同一侧。一旦出现异侧有相同颜色的节点,就说明该图不是二分图了。

总结一下:首先求出图的补图,然后把点双连通分量找出,对于每个双连通分量判断是否为二分图,如果不是则将分量重的所有点标记,统计一下标记过的顶点个数ans,最后结果就是n-ans。

AC代码:

 #include<cstdio>
#include<cstring>
const int N=+;
struct EDGE{
int v,next;
}edge[N*N*];
int g,cnt,top,count,n,m;
int first[N],low[N],dfn[N],sta[N*N*],sm[N],map[N][N],color[N],part[N],mark[N];
int min(int a,int b)
{
return a<b?a:b;
}
void AddEdge(int u,int v) //建边
{
edge[g].v=v;
edge[g].next=first[u];
first[u]=g++;
}
int dfscol(int u,int col) //交叉染色法
{
int i,v;
color[u]=col;
for(i=first[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(!part[v])
continue;
if(color[v]==col)
return ;
if(color[v]==&&dfscol(v,-col))
return ;
}
return ;
}
void color_solve() //二分判定
{
int i;
memset(part,,sizeof(part));
for(i=;i<count;i++)
part[sm[i]]=;
memset(color,,sizeof(color));
if(dfscol(sm[],)) //若含有奇圈
{
for(i=;i<count;i++)
mark[sm[i]]=;
}
}
void Tarjan(int u,int fa) //求双连通分量
{
int i,v;
low[u]=dfn[u]=++cnt;
sta[top++]=u;
for(i=first[u];i!=-;i=edge[i].next)
{
v=edge[i].v;
if(i==(fa^))
continue;
if(!dfn[v])
{
Tarjan(v,i);
low[u]=min(low[u],low[v]);
if(low[v]>=dfn[u])
{
count=; //将双连通分量记录起来。。刚开始这部分写错了,wa到死
sm[count++]=u;
sta[top]=-;
while(sta[top]!=v) //注意割点属于多个双连通分量,所以要弹到v,u不能弹出去
{
sm[count++]=sta[--top];
}
color_solve(); //判断该双连通分量是否为二分图
}
}
else
low[u]=min(low[u],dfn[v]);
}
}
void solve()
{
int i,j,u,v;
g=cnt=top=; //初始化
memset(low,,sizeof(low));
memset(dfn,,sizeof(dfn));
memset(first,-,sizeof(first));
memset(map,,sizeof(map));
memset(mark,,sizeof(mark)); for(i=;i<m;i++)
{
scanf("%d%d",&u,&v);
map[u][v]=map[v][u]=;
}
for(i=;i<=n;i++) //建反图
for(j=i+;j<=n;j++)
{
if(!map[i][j])
{
AddEdge(i,j);
AddEdge(j,i);
}
}
for(i=;i<=n;i++) //求双连通分量
if(!dfn[i])
Tarjan(i,-); int ans=;
for(i=;i<=n;i++) //统计已标记的顶点数
if(mark[i])
ans++;
printf("%d\n",n-ans);
}
int main()
{
while(scanf("%d%d",&n,&m))
{
if(n==&&m==)
break;
solve();
}
return ;
}

poj 2942 Knights of the Round Table(点双连通分量+二分图判定)的更多相关文章

  1. POJ 2942 Knights of the Round Table(双连通分量)

    http://poj.org/problem?id=2942 题意 :n个骑士举行圆桌会议,每次会议应至少3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置.如果意见发生分歧,则需要举手表决,因此 ...

  2. POJ2942 Knights of the Round Table 点双连通分量 二分图判定

    题目大意 有N个骑士,给出某些骑士之间的仇恨关系,每次开会时会选一些骑士开,骑士们会围坐在一个圆桌旁.一次会议能够顺利举行,要满足两个条件:1.任意相互憎恨的两个骑士不能相邻.2.开会人数为大于2的奇 ...

  3. 【POJ】2942 Knights of the Round Table(双连通分量)

    http://poj.org/problem?id=2942 各种逗.... 翻译白书上有:看了白书和网上的标程,学习了..orz. 双连通分量就是先找出割点,然后用个栈在找出割点前维护子树,最后如果 ...

  4. POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]

    Knights of the Round Table Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 12439   Acce ...

  5. POJ 2942.Knights of the Round Table (双连通)

    简要题解: 意在判断哪些点在一个图的  奇环的双连通分量内. tarjan求出所有的点双连通分量,再用二分图染色判断每个双连通分量是否形成了奇环,记录哪些点出现在内奇环内 输出没有在奇环内的点的数目 ...

  6. POJ - 2942 Knights of the Round Table (点双联通分量+二分图判定)

    题意:有N个人要参加会议,围圈而坐,需要举手表决,所以每次会议都必须是奇数个人参加.有M对人互相讨厌,他们的座位不能相邻.问有多少人任意一场会议都不能出席. 分析:给出的M条关系是讨厌,将每个人视作点 ...

  7. UVALive-3523 Knights of the Round Table (双连通分量+二分图匹配)

    题目大意:有n个骑士要在圆桌上开会,但是相互憎恶的两个骑士不能相邻,现在已知骑士们之间的憎恶关系,问有几个骑士一定不能参加会议.参会骑士至少有3个且有奇数个. 题目分析:在可以相邻的骑士之间连一条无向 ...

  8. POJ 2942 Knights of the Round Table 黑白着色+点双连通分量

    题目来源:POJ 2942 Knights of the Round Table 题意:统计多个个骑士不能參加随意一场会议 每场会议必须至少三个人 排成一个圈 而且相邻的人不能有矛盾 题目给出若干个条 ...

  9. poj 2942 Knights of the Round Table - Tarjan

    Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress ...

随机推荐

  1. spring学习笔记 星球日two - 注解方式配置bean

    注解要放在要注解的对象的上方 @Autowired private Category category; <?xml version="1.0" encoding=" ...

  2. 菜鸟vimer成长记——第2.4章、cmd-line模式

    cmd-line模式又有3个类型:Ex 命令(ex commands).查找模式(Search patterns).Filter 命令(Filter commands).本文主要重点的是Ex 命令和S ...

  3. 修复bug有哪些更快的技术?做好这6点就够了

    你有没有想过为什么有时修复错误似乎比它应该花费更长的时间?当你终于找到问题时,事实证明你所需要的只是一个小小的改变.然而,花了很多时间才能找到正在发生的事情.这种情况比我想象的更频繁. 另一方面,当您 ...

  4. Python+Selenium UI自动化测试环境搭建及使用

    一什么是Selenium ? Selenium 是一个浏览器自动化测试框架,它主要用于web应用程序的自动化测试,其主要特点如下:开源.免费:多平台.浏览器.多语言支持:对web页面有良好的支持:AP ...

  5. CentOS 7.X下 -- 配置nginx正向代理支持https

    环境说明: 本次测试使用的操作系统为:CentOS 7.2 x86 64位 最小化安装的操作系统,系统基础优化请参考:https://www.cnblogs.com/hei-ma/p/9506623. ...

  6. WebGL——osg框架学习一

    从今天开始,我们开始正式的学习osg框架,今天我们学习的是osg的渲染模块,我们来看一下代码结构. 所有DrawXXX的js模块都是渲染的模块,我们逐一来简单介绍一下,第一个Drawable.js,这 ...

  7. Java的POI的封装与应用

    Java对Excel表格的导出一直是对我有种可怕噩梦的东西,每次对要建立行与列,并一个一个放值,我是从心底拒绝的. 处于项目需求,需要导出表格,于是找到网上一版很好的开发, <不想用POI?几行 ...

  8. .NetCore下使用EF DbFirst操作MySql

    新建.NetCore的控制台项目 使用Nuget安装Pomelo.entityframeworkcore.mysql 工程右键--->编辑.csproj文件,把以下内容写入到工程文件 <I ...

  9. django orm 操作表

    django orm 操作表 1.基本操作 增 models.Tb1.objects.create(c1='xx', c2='oo') 增加一条数据,可以接受字典类型数据 **kwargs inser ...

  10. 第五章 if语句

    5.2条件测试 使用==判断相当: 使用!=判断不相等: 每条if语句的核心都是一个值为Tre或False的表达式,这种表达式被称为条件测试,如果条件测试的值为Ture,则执行紧跟在if语句后面的代码 ...