圆桌骑士,记得小时候街机也有同名还蛮喜欢玩的游戏。
题意:有n个骑士经常举行圆桌会议,商讨大事~每次圆桌会议至少应有3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置。如果发生意见分歧,则需要举手表决,因此参加会议的骑士数目必须是奇数以防止赞同票和反对票一样多。知道了哪些骑士相互憎恨之后,你的任务是统计有多少个骑士不可能参加任何一个会议。(题意来自刘汝佳白书)
首先可以对不相互憎恨的骑士建边,然后找出所有的双连通分量,对于每一个双连通分量,只要有一个奇圈,连通分量李所有的人都可以参加了,这个自己画个图最直接了。
模板题,好好弄好图论基础!
#include <stdio.h>
#include <string.h>
#include <vector>
using namespace std;
#define pb push_back
const int maxn = 1005;
const int maxm = 1000005;
struct EDGE{
int u, to, next, vis;
}edge[maxm<<1];
int head[maxn], hate[maxn][maxn], dfn[maxn], st[maxm], color[maxn], isodd[maxn], low[maxn];
int E, time, top, btot;
void newedge(int u, int to) {
edge[E].to = to;
edge[E].u = u;
edge[E].vis = 0;
edge[E].next = head[u];
head[u] = E++;
}
int min(int a, int b) {
return a > b ? b : a;
}
vector <int> block[maxn];
void dfs(int u) {
dfn[u] = low[u] = ++time;
for(int i = head[u];i != -1;i = edge[i].next) {
if(edge[i].vis) continue;
edge[i].vis = edge[i^1].vis = 1;
int to = edge[i].to;
st[++top] = i;
if(!dfn[to]) {
dfs(to);
low[u] = min(low[u], low[to]);
if(low[to] >= dfn[u]) {
btot++;
block[btot].clear();
do {
int now = st[top--];
block[btot].pb(now);
to = edge[now].u;
} while(to != u);
}
}
else
low[u] = min(low[u], low[to]);
}
}
int flag;
void DFS(int u) {
for(int i = head[u];i != -1;i = edge[i].next) {
if(edge[i].vis) continue;
edge[i].vis = edge[i^1].vis = 1;
int to = edge[i].to;
if(!color[to]) {
color[to] = 3 - color[u];
DFS(to);
}
else if(color[u] == color[to])
flag = 1;
}
}
void init() {
memset(head, -1, sizeof(head));
memset(dfn, 0, sizeof(dfn));
memset(hate, 0, sizeof(hate));
memset(isodd, 0, sizeof(isodd));
E = time = top = btot = 0;
}
int main() {
int n, m, i, j, u, to;
while(scanf("%d%d", &n, &m) != -1 && n) {
init();
for(i = 0;i < m; i++) {
scanf("%d%d", &u, &to);
hate[u][to] = hate[to][u] = 1;
}
for(i = 1;i <= n; i++) {
for(j = i+1;j <= n; j++) if(!hate[i][j]) {
newedge(i, j);
newedge(j, i);
}
}
for(i = 1;i <= n; i++) if(!dfn[i])
dfs(i);
for(i = 1;i <= btot; i++) {
if(block[i].size() == 1) continue;
int now = block[i][0];
u = edge[now].u;
for(j = 0;j < block[i].size(); j++)
edge[block[i][j]].vis = 0;
memset(color, 0, sizeof(color));
color[u] = 1;
flag = 0;
DFS(u);
if(flag)
for(j = 0;j < block[i].size(); j++) {
now = block[i][j];
isodd[edge[now].u] = isodd[edge[now].to] = 1;
}
}
int ans = 0;
for(i = 1;i <= n; i++) if(!isodd[i]) ans++;
printf("%d\n", ans);
}
return 0;
}