poj 2942 Knights of the Round Table(点双连通分量+二分图判定)
2013-09-27 00:28
453 查看
题目链接: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代码:
View Code
题意: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=1000+5; struct EDGE{ int v,next; }edge[N*N*2]; int g,cnt,top,count,n,m; int first ,low ,dfn ,sta[N*N*2],sm ,map ,color ,part ,mark ; 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!=-1;i=edge[i].next) { v=edge[i].v; if(!part[v]) continue; if(color[v]==col) return 1; if(color[v]==0&&dfscol(v,-col)) return 1; } return 0; } void color_solve() //二分判定 { int i; memset(part,0,sizeof(part)); for(i=0;i<count;i++) part[sm[i]]=1; memset(color,0,sizeof(color)); if(dfscol(sm[0],1)) //若含有奇圈 { for(i=0;i<count;i++) mark[sm[i]]=1; } } void Tarjan(int u,int fa) //求双连通分量 { int i,v; low[u]=dfn[u]=++cnt; sta[top++]=u; for(i=first[u];i!=-1;i=edge[i].next) { v=edge[i].v; if(i==(fa^1)) continue; if(!dfn[v]) { Tarjan(v,i); low[u]=min(low[u],low[v]); if(low[v]>=dfn[u]) { count=0; //将双连通分量记录起来。。刚开始这部分写错了,wa到死 sm[count++]=u; sta[top]=-1; 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=0; //初始化 memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(first,-1,sizeof(first)); memset(map,0,sizeof(map)); memset(mark,0,sizeof(mark)); for(i=0;i<m;i++) { scanf("%d%d",&u,&v); map[u][v]=map[v][u]=1; } for(i=1;i<=n;i++) //建反图 for(j=i+1;j<=n;j++) { if(!map[i][j]) { AddEdge(i,j); AddEdge(j,i); } } for(i=1;i<=n;i++) //求双连通分量 if(!dfn[i]) Tarjan(i,-1); int ans=0; for(i=1;i<=n;i++) //统计已标记的顶点数 if(mark[i]) ans++; printf("%d\n",n-ans); } int main() { while(scanf("%d%d",&n,&m)) { if(n==0&&m==0) break; solve(); } return 0; }
View Code
相关文章推荐
- poj 2942 Knights of the Round Table(无向图的双连通分量+二分图判定)
- poj 2942 Knights of the Round Table(无向图的双连通分量+二分图判定)
- POJ_2942_Knights of the Round Table(点的双连通分量+二分图判定)
- POJ 2942 Knights of the Round Table ★(点双连通分量+二分图判定)
- POJ 2942 Knights of the Round Table ★(点双连通分量+二分图判定)
- 【连通图|双连通+二分图判定】POJ-2942 Knights of the Round Table
- POJ 2942 Knights of the Round Table(双连通分量+二分图)
- poj2942 Knights of the Round Table,无向图点双联通,二分图判定
- POJ 2942 Knights of the Round Table(【点双连通分量】+【二分图判定】)
- poj2942 Knights of the Round Table,无向图点双联通,二分图判定
- poj 2942 Knights of the Round Table(双连通分量+tarjan+二分图判定)
- poj 2942 Knights of the Round Table 补图+点双连通分量+判定二分图
- POJ2942 Knights of the Round Table(点双连通分量 + 二分图染色)
- POJ 2942 Knights of the Round Table(点双联通+二分图+染色)
- POJ 2942 - Knights of the Round Table(点双联通+二分图)
- POJ 2942 - Knights of the Round Table(双连通图 Tarjan + 二分判定)
- POJ 2942:Knights of the Round Table tarjan点双联通分量 二分图染色找奇环
- POJ 2942 Knights of the Round Table 【点双联通 + 二分图染色法判奇环】
- poj 2942 Knights of the Round Table Tarjan求点双联通分量+黑白染色二分图判断
- POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]