圆桌骑士,记得小时候街机也有同名还蛮喜欢玩的游戏。
题意:有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; }