POJ 2942 Knights of the Round Table


题目描述:
武士是一个十分吸引人的职业,因此近年来Arthur王国武士的数量得到了空前的增长。武士
在讨论事情时很容易激动,特别是喝了酒以后。在发现一些不幸的打斗后,Arthur国王要求智者
Merlin确保将来不会发生武士的打斗。
Merlin在仔细研究这个问题后,他意识到如果武士围着圆桌坐下,要阻止打斗则必须遵循以
下两个规则:
(1) 任何两个互相仇视的武士不能挨着坐,Merlin有一张清单,列出了互相仇视的武士,注意,
武士是围着圆桌坐下的,每个武士有两个相邻的武士。
(2) 围着圆桌坐下的武士数量必须为奇数个。这将能保证当武士在争论一些事情时,能通过投
票的方式解决争端。而如果武士数量为偶数个,则可能会出现赞同和反对的武士数量一样。
如果以上两个条件满足,Merlin将让这些武士围着圆桌坐下,否则他将取消圆桌会议。如果
只有一个武士到了,Merlin也将取消会议,因为一个武士无法围着圆桌坐下。Merlin意识到如果
遵守以上两个规则,可能会使某些武士不可能被安排坐下,一个例子是如果一个武士仇视其他每
个武士。如果一个武士不可能被安排坐下,他将被从武士名单中剔除掉。你的任务是帮助Merlin
判断有多少个武士将会被剔除掉。
输入描述:
输入文件中包含多个测试数据。每个测试数据第1行为两个整数n和m,1≤n≤1000,1≤
m≤1000000,n表示武士数目,n个武士编号为1~n,m表示武士相互仇视的对数。接下来有
m行,描述了相互仇视的每对武士,每行为两个整数k1和k2,表示武士k1和k2相互仇视。
n = m = 0表示输入结束。
输出描述:
对输入文件中的每个测试数据,输出一行,为从名单中被剔除掉的武士数目。


// 开始理解错题目意思了 一直以为要大家同时坐下去 问有哪些人不能坐 发现自己二了
// 那样真的怎么动手都不知道
// 求无向图的双连通分量 (tarjan算法) 并判断奇圈(通过奇偶染色)
// 主要是只要是点数大于2的非二分图 而且双连通 那么每个点坑定肯定会在某个奇圈里面
// 首先要理解 点数大于2的非二分图 而且双连通 那么里面肯定含有奇圈 可以用反证法法去理解
// 那么 某个在这个奇圈外的点 u 与奇圈内的两点u1 u2有2条路径 而且这2条路径完全不重叠,所经过的点都不同 不然就有割点存在了 (由双连通性质决定)
// 那么 由于 u1 u2两点在奇圈内距离一奇一偶 那么就可让u这个点进入一个奇圈
// 所以 点数大于2 非二分图 就是可以一起开会的了
// 还有 二分图不存在奇圈 也可以用反证法去理解

#include <iostream> #include <algorithm> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <string.h> using namespace std; #define MOD 1000000007 #define maxn 1000010 #define maxm 1010 struct Edge{ int to; int next; Edge(){}; Edge(int u,int v){to=u;next=v;} }E[maxn]; int V[maxm],num; int pre[maxm]; int dfst,bcc; stack<Edge> S; vector<int> bccno[maxm]; int belong[maxm]; int clor[maxm]; bool ans[maxm]; bool A[maxm][maxm]; void init(){ dfst=0; num=0; bcc=0; while(!S.empty()) S.pop(); memset(V,-1,sizeof(V)); memset(pre,0,sizeof(pre)); memset(ans,0,sizeof(ans)); memset(A,0,sizeof(A)); memset(belong,0,sizeof(belong)); } void add(int u,int v){ E[num].to=v; E[num].next=V[u]; V[u]=num++; E[num].to=u; E[num].next=V[v]; V[v]=num++; } int dfs(int u,int fa){ int lowu; // printf("?"); Edge x; lowu=pre[u]=++dfst; int v,e; for(e=V[u];e!=-1;e=E[e].next){ v=E[e].to; if(!pre[v]){ S.push(Edge(u,v));// 压边进去 int lowv=dfs(v,u); // printf(" %d %d\n",u,lowv); lowu=min(lowu,lowv); if(lowv>=pre[u]){ bcc++;bccno[bcc].clear(); for(;;){ // 将形成双连通的部分的点放在一起 x=S.top();S.pop(); // printf("%d %d ",x.to,x.next); if(belong[x.to]!=bcc){bccno[bcc].push_back(x.to);belong[x.to]=bcc; } if(belong[x.next]!=bcc){bccno[bcc].push_back(x.next);belong[x.next]=bcc; } if(x.to==u&&x.next==v) break; } // printf(" u= %d\n",bcc); } } else if(v!=fa) lowu=min(lowu,pre[v]); } return lowu; } bool color(int u,int kind){ int e,v; for(e=V[u];e!=-1;e=E[e].next){ v=E[e].to; if(belong[v]!=kind) continue;//printf("kind %d %d \n",u,v); if(clor[v]==clor[u]) return false; if(!clor[v]){ clor[v]=3-clor[u]; if(!color(v,kind)) return false; } } return true; } int main() { int n,m; int u,v; int i,j; while(scanf("%d %d",&n,&m),n|m){ init(); for(i=1;i<=m;i++){ scanf("%d %d",&u,&v); A[u][v]=1; A[v][u]=1; } for(i=1;i<=n;i++) for(j=i+1;j<=n;j++) if(!A[i][j]) add(i,j); for(i=1;i<=n;i++) if(!pre[i]) dfs(i,0); for(i=1;i<=bcc;i++){ memset(clor,0,sizeof(clor)); for(j=0;j<bccno[i].size();j++) belong[bccno[i][j]]=i;// 处理 割点 u=bccno[i][0]; clor[u]=1; if(!color(u,i)){// printf("%d %d ",u,i); for(j=0;j<bccno[i].size();j++) ans[bccno[i][j]]=true; } } int out=n; for(i=1;i<=n;i++) if(ans[i]) out--; printf("%d\n",out); } return 0; }

 

posted on 2013-07-21 20:25  江财小子  阅读(236)  评论(0编辑  收藏  举报