题意:
n
n
个骑士和组关系,每组关系表示两个骑士相互憎恨,相互憎恨的骑士不能在参加一场会议相邻着坐,而且每次会议参加的人数必须为奇数(
⩾3
⩾
3
),问多少骑士一定不能参加会议。
思路:
参照刘汝佳入门经典,可以相邻坐的骑士连边,求出双连通分量,然后保证双连通分量里面有奇环即可, 判断是否有奇环可以染色操作。
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e3 + 10;
using namespace std;
typedef pair<int, int> pa;
int pre[maxn], iscut[maxn], bccno[maxn];
int dfs_clock, bcc_cnt;
vector<int> G[maxn], bcc[maxn];
stack<pa> stk;
int n, m, T, kase = 1;
int dfs(int u, int fa) {
int lowu = pre[u] = ++dfs_clock;
int child = 0;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
pa e = pa(u, v);
if(!pre[v]) {
stk.push(e); child++;
int lowv = dfs(v, u);
lowu = min(lowu, lowv);
if(lowv >= pre[u]) { ///割点
iscut[u] = 1;
bcc_cnt++; bcc[bcc_cnt].clear();
while(1) {
pa x = stk.top(); stk.pop();
if(bccno[x.first] != bcc_cnt) {
bcc[bcc_cnt].push_back(x.first);
bccno[x.first] = bcc_cnt;
}
if(bccno[x.second] != bcc_cnt) {
bcc[bcc_cnt].push_back(x.second);
bccno[x.second] = bcc_cnt;
}
if(x.first == u && x.second == v) break;
}
}
} else if(pre[v] < pre[u] && v != fa) {
stk.push(e);
lowu = min(lowu, pre[v]);
}
}
if(fa < 0 && child == 1) iscut[u] = 0; ///根节点
return lowu;
}
int not_can[maxn][maxn];
int can_join[maxn], col[maxn], b[maxn];
bool __find(int x, int c, int blk) {
col[x] = c;
for(int i = 0; i < G[x].size(); i++) {
int v = G[x][i];
if(b[v] != blk) continue;
if(col[v] == -1 && __find(v, c ^ 1, blk)) return true;;
if(~col[v] && col[v] == col[x]) return true;
}
return false;
}
int main() {
while(scanf("%d %d", &n, &m) && (n + m)) {
memset(not_can, 0, sizeof not_can);
while(!stk.empty()) stk.pop();
dfs_clock = bcc_cnt = 0;
for(int i = 1; i <= n; i++) {
G[i].clear(); bcc[i].clear();
can_join[i] = 0; col[i] = -1;
pre[i] = iscut[i] = bccno[i] = 0;
}
while(m--) {
int u, v; scanf("%d %d", &u, &v);
not_can[u][v] = not_can[v][u] = 1;
}
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
if(not_can[i][j]) continue;
G[i].push_back(j);
G[j].push_back(i);
}
}
for(int i = 1; i <= n; i++) if(!pre[i]) dfs(i, -1);
for(int i = 1; i <= bcc_cnt; i++) {
for(int j = 0; j < bcc[i].size(); j++) {
b[bcc[i][j]] = i;
col[bcc[i][j]] = -1;
}
bool can = __find(bcc[i][0], 1, i);
if(!can || bcc[i].size() == 1) continue;
for(int j = 0; j < bcc[i].size(); j++) can_join[bcc[i][j]] = 1;
}
int ans = 0;
for(int i = 1; i <= n; i++) ans += can_join[i];
printf("%d\n", n - ans);
}
return 0;
}