题目链接: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. Redis 为什么使用单进程单线程方式也这么快

    Redis 采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由 C 语言编写.官方提供的数据是可以达到100000+的 qps.这个数据不比采用单进程多线程的同样基于内存的 KV 数据库 ...

  2. Python函数之总结

    ''' 1.什么是函数 函数就是具备某一特定功能的工具 2.为什么用函数 减少重复代码 增强程序的扩展性 增强可读性 3.如何用函数 1.函数的使用原则:先定义后调用(*****) 定义阶段:只检测语 ...

  3. java多线程系列(二)---对象变量并发访问

    对象变量的并发访问 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我 ...

  4. 基于Cocos2d-x-1.0.1的飞机大战游戏迁移到Cocos2d-x-3.0版本,并移植到Android平台成功运行

    一.版本迁移中的问题 1.游戏元素Sprite.Label.Action等等的创建函数名都改为create. 2.函数的回调callfunc_selectorcallfuncN_selectorcal ...

  5. centos安装及Xshell连接配置

    一.百度下载并安装VMware 二.下载centos 打开https://www.centos.org,点击“get centos now”,点击“DVD ISO”下载(也可以下滑点击“more do ...

  6. python自动化17-JS处理滚动条

    前言 selenium并不是万能的,有时候页面上操作无法实现的,这时候就需要借助JS来完成了. 常见场景: 当页面上的元素超过一屏后,想操作屏幕下方的元素,是不能直接定位到,会报元素不可见的. 这时候 ...

  7. TPO-22 C2 Revise a music history paper

    第 1 段 1.Listen to part of a conversation between a student and his music history professor. :听一段学生和音 ...

  8. Memcached服务器上实现多个实例(约约问题排查)

    约约测试服上出行一个问题,司机收车失败. (1)经查看代码是null指针异常. 针对,之前,同套代码发布到华威测试服,未出现该问题,遂认定不是代码问题. (2)打印异常信息,获取null值异常的收车司 ...

  9. Linux 文件搜索命令:find、which、whereis 和 locate

    Linux 提供了许多用于文件搜索的命令,这些命令都很强大,但是也有一些不同之处,这里分别介绍一下. 一.find 命令 find 是最常见和最强大的一个文件搜索命令.使用 find 命令可以在指定目 ...

  10. 【NLP】使用bert

    # 参考 https://blog.csdn.net/luoyexuge/article/details/84939755 小做改动 需要: github上下载bert的代码:https://gith ...