POJ 2942 Knights of the Round Table
2010-09-01 19:02
393 查看
用了好几天的时间,终于把这一块的知识弄懂了.....
题目大意:N个骑士中某些骑士之间会有仇恨。骑士们开会时围坐在一个圆桌旁。一次会议能够举行,当且仅当没有相邻的两个骑士相互仇恨,且开会人数为大于2的奇数。若某个骑士任何会议都不能参加,那么就必须将它踢出。给出骑士之间的仇恨关系,问需要踢出多少个骑士。
解题思路:先将所有的骑士看成一个点,如果两个骑士间有仇恨,那么他们之间就连一条边,这样就形成了一个有n个点的图,然后我们再求出此图的补图。显然这个补图中相连的两个点是不存在仇恨的。再求这个补图的点双连通分量(块),在这个双连通分量内,任何两点都存在两条路径可以到达而且这两条路径不能存在公共点(除了两个端点外)。如果在这个强连通分量中存在一个奇圈,显然在这个连通分量中的任何一个点都会在某个奇圈中(可证)。判断是否存在奇圈的方法就是使用两种颜色对这个分量进行染色。我们可以使用DFS进行处理(曾经很傻地用bfs做,╮(╯▽╰)╭)。如果存在一个点和其子节点颜色相同,那么这个连通分量中就存在奇圈了。那么答案就是所有不在任何奇圈中的骑士的个数。
题目大意:N个骑士中某些骑士之间会有仇恨。骑士们开会时围坐在一个圆桌旁。一次会议能够举行,当且仅当没有相邻的两个骑士相互仇恨,且开会人数为大于2的奇数。若某个骑士任何会议都不能参加,那么就必须将它踢出。给出骑士之间的仇恨关系,问需要踢出多少个骑士。
解题思路:先将所有的骑士看成一个点,如果两个骑士间有仇恨,那么他们之间就连一条边,这样就形成了一个有n个点的图,然后我们再求出此图的补图。显然这个补图中相连的两个点是不存在仇恨的。再求这个补图的点双连通分量(块),在这个双连通分量内,任何两点都存在两条路径可以到达而且这两条路径不能存在公共点(除了两个端点外)。如果在这个强连通分量中存在一个奇圈,显然在这个连通分量中的任何一个点都会在某个奇圈中(可证)。判断是否存在奇圈的方法就是使用两种颜色对这个分量进行染色。我们可以使用DFS进行处理(曾经很傻地用bfs做,╮(╯▽╰)╭)。如果存在一个点和其子节点颜色相同,那么这个连通分量中就存在奇圈了。那么答案就是所有不在任何奇圈中的骑士的个数。
#define MAXN 1002 #include <cstring> #include <cstdio> #include <iostream> using namespace std; int mat[MAXN][MAXN],n,dfn[MAXN],low[MAXN],cnt,st[MAXN],sp,ans[MAXN][MAXN],row,col; int color[MAXN]; //不在block内0,在内未访问1,两种颜色2,3 bool ok[MAXN],finish; void init() { memset(dfn,0,sizeof(dfn)); memset(ans,-1,sizeof(ans)); cnt=sp=row=0; memset(color,0,sizeof(color)); memset(ok,0,sizeof(ok)); } void search(int now) { dfn[st[sp++]=now]=low[now]=++cnt; for (int i=0; i<n; i++) if (mat[now][i]) { if (!dfn[i]) { search(i); if (low[i]<low[now]) low[now]=low[i]; if (low[i]>=dfn[now]) { for (st[sp]=-1,ans[row][0]=now,col=1; st[sp]!=i; ans[row][col++]=st[--sp]); if(col>2) row++; } } else if (dfn[i]<low[now]) low[now]=dfn[i]; } } void block() { for (int i=0; i<n; i++) if (!dfn[i]) search(i); } void dfs(int fa,int now,int co) { if(finish) return; for(int i=0;i<n;++i) { if(mat[now][i]&&color[i]!=0&&i!=fa&&i!=now) { if(color[i]==1) { color[i]=5-co; dfs(now,i,5-co); } else if(color[i]==color[now]) { finish=true; return; } } } } void setColor(int kind) { int now=0,cur,nxtcolor; while(ans[kind][now]!=-1) { color[ans[kind][now]]=1; ++now; } finish=false; color[ans[kind][0]]=2; dfs(-1,ans[kind][0],2); now=0; while(ans[kind][now]!=-1) { color[ans[kind][now]]=0; if(finish) ok[ans[kind][now]]=true; ++now; } } int main(void) { int m,a,b,res; scanf("%d%d",&n,&m); while(n!=0) { init(); for(int i=0;i<n;i++) for(int j=0;j<n;j++) mat[i][j]=1; while(m--) { scanf("%d%d",&a,&b); --a; --b; mat[a][b]=0; mat[b][a]=0; } block(); for(int i=0;i<row;++i) setColor(i); res=0; for(int i=0;i<n;++i) if(ok[i]==false) res++; printf("%d/n",res); scanf("%d%d",&n,&m); } return 0; }
相关文章推荐
- poj 2942 Knights of the Round Table 【双连通缩点+判奇圈】【经典】
- poj 2942 Knights of the Round Table
- POJ2942-Knights of the Round Table
- POJ2942 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(点的双连通分量+二分图判定)
- 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(无向图的双连通分量+二分图判定)
- poj 2942 Knights of the Round Table 点-双连通分量 图论综合题
- POJ 2942 Knights of the Round Table 点全连通分量 + DFS染色 做的好辛苦
- POJ 2942 Knights of the Round Table
- poj2942 Knights of the Round Table
- poj 2942 Knights of the Round Table(补图的求取+双连通分量+奇环的判断)