参考了题解将这题的代码写了一遍,整体来说收获还是比较大的。用邻接矩阵g存骑士的关系,
相互憎恨就连一条边。然后建立图g的补图,这里用邻接表会更好,表示这些骑士是可以相邻
的。然后用tarjan算法求补图的双连通分量,注意题目要求骑士g要在奇圈中。
传送门:http://blog.csdn.net/lyy289065406/article/details/6756821
有详细分析过程,膜拜下。
/*Accepted 8468K 1266MS C++ 2516B 2012-07-29 15:29:42*/ #include<cstdio> #include<cstring> #include<cstdlib> const int MAXN = 1 << 10; const int MAXM = MAXN * MAXN; int v[MAXM], first[MAXM], next[MAXM], s[MAXN], dfn[MAXN], low[MAXN]; int remain[MAXN], color[MAXN], recolor[MAXN], g[MAXN][MAXN]; int N, M, e, top, col, cnt; void addedge(int x, int y) { v[e] = y; next[e] = first[x], first[x] = e ++; } int dfs(int cur, int c) { recolor[cur] = c; for(int i = first[cur]; i != -1; i = next[i]) { if(color[v[i]] == color[cur]) { if(recolor[v[i]]) { if(recolor[v[i]] == c) return 1; } else if(dfs(v[i], -c)) return 1; } } return 0; } void tarjan(int cur) { int i, j, k; low[cur] = dfn[cur] = ++ cnt; s[top ++] = cur; for(i = first[cur]; i != -1; i = next[i]) { if(!dfn[v[i]]) { tarjan(v[i]); if(low[v[i]] < low[cur]) low[cur] = low[v[i]]; else if(low[v[i]] == dfn[cur]) { ++ col; for(j = top; s[j] != v[i]; ) color[s[-- j]] = col; color[cur] = col; memset(recolor, 0, sizeof recolor); if(dfs(cur, 1)) { for(k = j; k < top; k ++) remain[s[k]] = 1; remain[cur] = 1; } top = j; } } else if(dfn[v[i]] < low[cur]) low[cur] = dfn[v[i]]; } } void ReadGraph() { int i, j, x, y; memset(g, 0, sizeof g); for(i = 0; i < M; i ++) { scanf("%d%d", &x, &y); g[x][y] = g[y][x] = 1; } memset(first, -1, sizeof first); e = 0; for(i = 1; i <= N; i ++) for(j = i + 1; j <= N; j ++) if(!g[i][j]) addedge(i, j), addedge(j, i); } void solve() { int i, ans = 0; top = cnt = col = 0; memset(dfn, 0, sizeof dfn); memset(color, 0, sizeof color); memset(remain, 0, sizeof remain); for(i = 1; i <= N; i ++) if(!dfn[i]) tarjan(i); for(i = 1; i <= N; i ++) if(remain[i] == 0) ++ ans; printf("%d\n", ans); } int main() { while(scanf("%d%d", &N, &M), N || M) { ReadGraph(); solve(); } return 0; }