poj 2942 Knights of the Round Table(点双连通分量+二分图判定)
题目链接: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(点双连通分量+二分图判定)的更多相关文章
- POJ 2942 Knights of the Round Table(双连通分量)
http://poj.org/problem?id=2942 题意 :n个骑士举行圆桌会议,每次会议应至少3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置.如果意见发生分歧,则需要举手表决,因此 ...
- POJ2942 Knights of the Round Table 点双连通分量 二分图判定
题目大意 有N个骑士,给出某些骑士之间的仇恨关系,每次开会时会选一些骑士开,骑士们会围坐在一个圆桌旁.一次会议能够顺利举行,要满足两个条件:1.任意相互憎恨的两个骑士不能相邻.2.开会人数为大于2的奇 ...
- 【POJ】2942 Knights of the Round Table(双连通分量)
http://poj.org/problem?id=2942 各种逗.... 翻译白书上有:看了白书和网上的标程,学习了..orz. 双连通分量就是先找出割点,然后用个栈在找出割点前维护子树,最后如果 ...
- POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]
Knights of the Round Table Time Limit: 7000MS Memory Limit: 65536K Total Submissions: 12439 Acce ...
- POJ 2942.Knights of the Round Table (双连通)
简要题解: 意在判断哪些点在一个图的 奇环的双连通分量内. tarjan求出所有的点双连通分量,再用二分图染色判断每个双连通分量是否形成了奇环,记录哪些点出现在内奇环内 输出没有在奇环内的点的数目 ...
- POJ - 2942 Knights of the Round Table (点双联通分量+二分图判定)
题意:有N个人要参加会议,围圈而坐,需要举手表决,所以每次会议都必须是奇数个人参加.有M对人互相讨厌,他们的座位不能相邻.问有多少人任意一场会议都不能出席. 分析:给出的M条关系是讨厌,将每个人视作点 ...
- UVALive-3523 Knights of the Round Table (双连通分量+二分图匹配)
题目大意:有n个骑士要在圆桌上开会,但是相互憎恶的两个骑士不能相邻,现在已知骑士们之间的憎恶关系,问有几个骑士一定不能参加会议.参会骑士至少有3个且有奇数个. 题目分析:在可以相邻的骑士之间连一条无向 ...
- POJ 2942 Knights of the Round Table 黑白着色+点双连通分量
题目来源:POJ 2942 Knights of the Round Table 题意:统计多个个骑士不能參加随意一场会议 每场会议必须至少三个人 排成一个圈 而且相邻的人不能有矛盾 题目给出若干个条 ...
- 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 ...
随机推荐
- 【HNOI2013】数列
题面 题解 设\(\{a_n\}\)为差分数组,可以得到柿子: \[ \begin{aligned} ans &= \sum_{a_1 = 1} ^ m \sum_{a_2 = 1} ^ m ...
- MIUI 10 已连接 但无法访问互联网 的解决方案
wifi为 DHCP 时,我发现得到的总是已经有机器在用的 192.168.1.9 这台机器, 所以只需要手动配置一下ip就行了,随便指定一个,然后ping一下,ping不通的话就配上,然后再重新连 ...
- idea中xml打开方式变成file,改回来
原文:https://blog.csdn.net/u012903926/article/details/80682885 创建了一个test文件,用的是普通text打开方式,然后你修改文件为test. ...
- jQuery中attr()函数 VS prop()函数
http://www.365mini.com/page/jquery-attr-vs-prop.htm 在jQuery中,attr()函数和prop()函数都用于设置或获取指定的属性,它们的参数和用法 ...
- tpshop购物网站价格筛选功能的测试用例设计
测试对象:红框内的“价格筛选功能” 以下是功能需求: 1. 除了空以外,输入框不能输入数字之外的内容. 备注:如果出现数字之外的内容,输入框禁止输入. 2. 输入框不能小于0 备注:如果出现小于0的数 ...
- WebGL2系列之实例数组(Instanced Arrays)
实例化数组 实例化是一种只调用一次渲染函数却能绘制出很多物体的技术,它节省渲染一个物体时从CPU到GPU的通信时间.实例数组是这样的一个对象,使用它,可以把原来的的uniform变量转换成attrib ...
- JVM类加载全过程--图解
JVM规范允许类加载器在预料某个类将要被使用时就预先加载它,下图为实例方法被调用时的JVM内存模型,1~7完整的描述了从类加载开始到方法执行前的预备过程,后面将对每一个步骤进行解释 在我们加载类的过程 ...
- ABP.ModuleZero.Feature——特性管理
原文地址:http://aspnetboilerplate.com/Pages/Documents/Feature-Management (在翻译原文的基础上增补更多细节说明) 简介 在大多数SAA ...
- Yii2 输出图片相关
http://www.yiichina.com/doc/api/2.0/yii-web-response#$format-detail https://segmentfault.com/q/10100 ...
- bootstrape3 模态
version 2 的模态 不能在 version 3 上面用. http://schy-hqh.iteye.com/blog/1995690