题目链接: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. AFO预定

    妈耶 数论题都不会 推不出式子 题解都看不懂 还是思维jiang化了 布星了 吃枣药丸 祝yyb进队 祝zsy进队 祝鸡贼进队

  2. 设计模式:代理模式 vs 装饰模式

    参考文章:https://www.cnblogs.com/luoxn28/p/5535877.html 代理模式和装饰模式非常类似,甚至代码都类似. 二者最主要的区别是: 代理模式中,代理类对被代理的 ...

  3. centos7 安装postgres9.4

    1.安装postgres资源:> yum install https://download.postgresql.org/pub/repos/yum/9.4/redhat/rhel-7-x86_ ...

  4. Famous框架系列一:famous/core/Surface

    famous/core/Surface 既然是Famous的第一篇文章,就先给Famous打个广告:http://periodic.famo.us  Famous12年的作品,点击右下角Fun thi ...

  5. 记一次eslint规则配置

    { // 环境定义了预定义的全局变量. "env": { //环境定义了预定义的全局变量.更多在官网查看 "browser": true, "node ...

  6. python简单计时器实现

    实现程序运行时间的显示与相互之间的计算: 实现代码: import time as t class Mytimer(): def __init__(self): self.unit=["年& ...

  7. c语言数字图像处理(八):噪声模型及均值滤波器

    图像退化/复原过程模型 高斯噪声 PDF(概率密度函数) 生成高斯随机数序列 算法可参考<http://www.doc.ic.ac.uk/~wl/papers/07/csur07dt.pdf&g ...

  8. Tomcat性能优化方案

    1. 提高JVM栈内存Increase JVM heap memory 你使用过tomcat的话,简单的说就是"内存溢出". 通常情况下,这种问题出现在实际的生产环境中.产生这种问 ...

  9. UnityEditor扩展-右键拷贝资源路径到系统剪贴板

    要点速记 命令添加到右键菜单 [MenuItem("Assets/Copy Asset Path")] 或 [MenuItem("Assets/Copy Asset Pa ...

  10. linux 启动自动运行

    开机启动时自动运行程序  Linux    1.加载后, 它将初始化硬件和设备驱动, 然后运行第一个进程init.init根据配置文件继续引导过程,启动其它进程.通常情况下,修改放置在 /etc/rc ...