[双连通] poj 2942 Knights of the Round Table#双连通+交叉染色
来源:互联网 发布:mysql 清空整个数据库 编辑:程序博客网 时间:2024/06/03 09:30
/**[双连通] poj 2942 Knights of the Round Table#割点+交叉染色题意,N个骑士中某些骑士之间会有仇恨。骑士们开会时围坐在一个圆桌旁。一次会议能够举行,当且仅当没有相邻的两个骑士相互仇恨,且开会人数为大于2的奇数。若某个骑士任何会议都不能参加,那么就必须将它踢出。给出骑士之间的仇恨关系,问需要踢出多少个骑士。建立输入图的补图,即没有仇恨关系的骑士建边Trajan算法找割点并记录双强连通分量;交叉染色搜索奇圈。若某块存在奇圈,那么该块中的所有点都存在于奇圈中,否则,全部删除*/#include <stdio.h>#include <string.h>#include <vector>#include <algorithm>using namespace std;#define N 1024vector<int> g[N];int dfn[N],color[N],low[N],stk[N],sp,used[N],typ,id[N];bool mat[N][N],vis[N];int m,n;bool bicolor(int u,int f,int cc){ color[u] = cc; for(int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(id[v] != id[u] || u == f) continue; if(color[v] == cc || (!color[v] && bicolor(v,u,-cc))) return 1; } return 0;}void dfs(int u,int f,int dep){ vis[u] = 1; low[u] = dfn[u] = dep; stk[sp++] = u; for(int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if(vis[v] && v != f) low[u] = min(low[u],dfn[v]); if(vis[v] == 0) { dfs(v,u,dep+1); low[u] = min(low[u],low[v]); if(low[v] >= dfn[u]) { int t,k = 0; do{ k++; id[t = stk[--sp]] = typ; }while(t != v); id[u] = typ; memset(color,0,sizeof(color)); if(k >= 2 && bicolor(u,0,1)) ///至少三人才可以 for(int j = 1; j <= n; ++j) if(id[j] == typ) used[j] = 1; ++typ; } } }}int main(){ int i,j; while(scanf("%d%d",&n,&m) != EOF && n) { memset(used,0,sizeof(used)); memset(mat,0,sizeof(mat)); memset(vis,0,sizeof(vis)); memset(id,0,sizeof(id)); memset(g,0,sizeof(g)); while(m--) { scanf("%d%d",&i,&j); mat[i][j] = mat[j][i] = 1; } for(i = 1; i <= n; ++i) for(j = 1; j <= n; ++j) if(i != j && !mat[i][j]) g[i].push_back(j); sp = 0; typ = 1; for(i = 1; i <= n; ++i) if(!vis[i]) dfs(i,0,1); int res = 0; for(i = 1; i <= n; ++i) res += !used[i]; printf("%d\n",res); } return 0;}