题目大意:
有N个骑士,他们要开圆桌会议,也就是要坐成一个圈,相互憎恨的两个骑士是不能坐在相邻位置的,那样他们就会打起来。给出所有的憎恨关系。如果有人不可能开会,例如他可能憎恨所有人,就不能再去开会了。求这样人的个数。
注意:1、所给出的憎恨关系一定是双向的,不存在单向憎恨关系。
2、由于是圆桌会议,则每个出席的骑士身边必定刚好有2个骑士。即每个骑士的座位两边都必定各有一个骑士。
3、一个骑士无法开会,就是说至少有3个骑士才可能开会。
思路:
1. 求补图(补图:图G的补图~G就是把图G原有的边全部删去,原本不存在的边全部连上。 )
2. 求双连通分量(双连通分量: 简单来说,无向图G如果是双连通的,那么至少要删除图G的2个结点才能使得图G不连通。换而言之,就是图G任意2个结点之间都存在两条以上的路径连接(注意:路径不是指直接相连的边),那么双连通分量就是指无向图G的子图G’是双连通了。 )
3. 找奇圈(奇圈是用一条线把奇数个点串连起来,所得到的闭合的圈就是奇圈了。其实奇圈就是有奇数个顶点的环。 )
一个重要的性质
若某块存在奇圈,那么该块中的所有点都存在与奇圈中
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#include <string>
#include <algorithm>
#define ll long long
using namespace std;
const int inf=0x3ffffff;
const int MAXN = 1003;
const double eps = 1e-6;
int edge[MAXN][MAXN];
int dfn[MAXN], low[MAXN], in_seq[MAXN];
int stack[MAXN], list[MAXN];
int cnt, top, pop, len;
int n, m;
bool flag[MAXN];
int color[MAXN];
bool paint(int u, int c){ //找奇圈
color[u] = c;
for (int i = 1; i <= n; i++) {
if (edge[u][i] && in_seq[i] == cnt) {
if (color[i] && color[i] == color[u]) {
return true;
}
if (!color[i] && paint(i, -c)) {
return true;
}
}
}
return false;
}
void biconnect(int v) {
stack[++top] = v;
dfn[v] = low[v] = pop++;
int i;
for (i = 1; i <= n; i++) {
if (edge[v][i]){
if (dfn[i] == -1) {
biconnect(i);
if (low[i] >= dfn[v]) {
cnt++;
len = 0;
do {
in_seq[stack[top]] = cnt;
list[len++] = stack[top];
top--;
} while(stack[top + 1] != i);
in_seq[v] = cnt;
list[len++] = v;
memset(color, 0, sizeof(color));
if (len >= 3 && paint(i, 1)){
for (int j = 0; j < len; j++) {
flag[list[j]] = true;
}
}
}
low[v] = min(low[v], low[i]);
} else {
low[v] = min(low[v], dfn[i]);
}
}
}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1.txt", "r", stdin);
#endif
int i, j, k, u, v;
while(cin >> n >> m, n) {
cnt = top = pop = 0;
memset(in_seq, 0, sizeof(in_seq));
memset(dfn, -1, sizeof(dfn));
memset(flag, false, sizeof(flag));
for (i = 0; i <= n; i++) {
for (j = 0; j < i; j++) {
edge[i][j] = edge[j][i] = true;
}
edge[i][i] = false;
}
for (i = 0; i < m; i++) {
scanf("%d%d", &u, &v);
edge[u][v] = edge[v][u] = false; //建立反向图
}
for (i = 1; i <= n; i++) {
if (dfn[i] == -1) {
biconnect(i);
}
}
int ans = 0;
for (i = 1; i <= n; i++) {
ans += flag[i];
}
cout << n-ans << endl;
}
return 0;
}