Knights of the Round Table
# Description
给定若干骑士和他们之间的仇恨关系,规定召开圆桌会议时,两个有仇恨的骑士不能坐在相邻位置,且召开一次圆桌会议的骑士人数必须为奇数,求有多少骑士永远不可能参加某一次圆桌会议。
# Format
## Input
多组数据,每组数据先给出N,M代表N个骑士和M组关系
接下来M行,每行两个数字
整个测试以0 0结束
1 ≤ n ≤ 1000
1 ≤ m ≤ 1000000
## Output
如题
# Samples
```input1
5 5
1 4
1 5
2 5
3 4
4 5
0 0
```
```output1
2
```
题解:
建图时,对互相不憎恨的两人之间连一条边。
对任意一名骑士来说,他要能出席某次会议则他左右的人都不能与他互相憎恨。
将每次参加会议的所有人(不一定是整个骑士团,只需人数>=3且为奇数)看做一个点双联通分量,那么每个点都至少有两个点与他相邻。即需要保证双联通分量中存在奇圈。
因为只要点双连通分量中存在奇圈,那么这个分量中所有的点都可以出现在奇圈上。
求奇圈时可以用到这样一个性质,一个图是二分图当且仅当图中不存在奇圈。
那么我们只需判断一个图是否是二分图就可以判断此图存在奇圈,可以用交替染色。
————————————————
版权声明:本文为CSDN博主「ConwayTian」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Tsaid/article/details/6895808
#include <iostream> #include <queue> #include <stdio.h> #include <cstring> #include <vector> const int maxn = 1e3 + 5; const int inf = 0x3f3f3f3f; using namespace std; vector<int> g[maxn]; int gg[maxn][maxn]; int dfn[maxn], low[maxn], vis[maxn], Stack[maxn], inStack[maxn]; int color[maxn]; int len, cnt, ts; int n, m; void init(int n) { len = cnt = ts = 0; for (int i = 1; i <= n; ++i) g[i].clear(); fill(vis, vis+n+1, 0); fill(dfn, dfn+n+1, 0); fill(gg[0], gg[0]+maxn*maxn, 0); } int check() { fill(color, color+maxn, -1); queue<int> que; for (int i = 1; i <= n; ++i) { if (inStack[i]) //找到一个在点双中的点 { que.push(i); color[i] = 0; break; } } while (!que.empty()) //做一次01染色 { int u = que.front(); que.pop(); for (int i = 0; i < (int)g[u].size(); ++i) { int v = g[u][i]; if (inStack[v] == 0) continue; if (color[v] == -1) //如果没染过色,则染上一个与u不同的色彩 { color[v] = color[u] ^ 1; que.push(v); } else //如果染过了的话,并且与u一样 //说明找到一个长度为奇数的环 if (color[v] == color[u]) return 1; } } return 0; } void tarjan(int u, int fa) { dfn[u] = low[u] = ++ts; Stack[len++] = u; for (int i = 0; i < (int)g[u].size(); ++i) { int v = g[u][i]; if (v == fa) continue; if (!dfn[v]) { tarjan(v, u); low[u] = min(low[u], low[v]); if (dfn[u] <= low[v]) { fill(inStack, inStack+n+1, 0); //instack为存放结果的 inStack[u] = 1; while (1) { int top = Stack[--len]; inStack[top] = 1; //top这个点在点双中 if (top == v) break; } if (check()) //如果是一个奇数环的话 { for (int i = 1; i <= n; ++i) { if (inStack[i]) vis[i] = 1; } } } } else low[u] = min(low[u], dfn[v]); } } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); while (scanf("%d %d", &n, &m), n) { init(n); for (int i = 0; i < m; ++i) { int u, v; scanf("%d%d", &u, &v); gg[u][v] = gg[v][u] = 1; } for (int i = 1; i <= n; ++i) { for (int j = 1; j <= n; ++j) { if (i == j || gg[i][j]) continue; g[i].push_back(j); } } for (int i = 1; i <= n; ++i) { if (dfn[i]) continue; tarjan(i, 0); } int ans = n; for (int i = 1; i <= n; ++i) ans -= vis[i]; printf("%d\n", ans); } return 0; }