/* ID: wuqi9395@126.com PROG: LANG: C++ */ #include<map> #include<set> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<string> #include<fstream> #include<cstring> #include<ctype.h> #include<iostream> #include<algorithm> using namespace std; #define INF (1<<30) #define PI acos(-1.0) #define mem(a, b) memset(a, b, sizeof(a)) #define rep(i, a, n) for (int i = a; i < n; i++) #define per(i, a, n) for (int i = n - 1; i >= a; i--) #define eps 1e-6 #define debug puts("===============") #define pb push_back #define mkp make_pair #define all(x) (x).begin(),(x).end() #define fi first #define se second #define SZ(x) ((int)(x).size()) #define POSIN(x,y) (0 <= (x) && (x) < n && 0 <= (y) && (y) < m) typedef long long ll; typedef unsigned long long ULL; const int maxn = 1100; int vis[maxn], bccno[maxn], dfn[maxn], low[maxn], cnt, n, m; //其中割点的bccno[]无意义 vector<int> g[maxn], bcc[maxn]; struct edge { int u, v; edge(int _u, int _v) { u = _u, v = _v; } }; stack<edge> s; void dfs(int u, int f, int dep) { vis[u] = 1; low[u] = dfn[u] = dep; int child = 0; for (int i = 0; i < g[u].size(); i++) if (g[u][i] != f) { int v = g[u][i]; edge e(u, v); if (vis[v] == 2) continue; s.push(e); if (vis[v] == 1 && dfn[v] < low[u]) low[u] = dfn[v]; if (vis[v] == 0) { dfs(v, u, dep + 1); child++; if (low[v] < low[u]) low[u] = low[v]; if (low[v] >= dfn[u]) { cnt++; bcc[cnt].clear(); //cnt从1开始! while(1) { edge x = s.top(); s.pop(); if (bccno[x.u] != cnt) bcc[cnt].push_back(x.u), bccno[x.u] = cnt; //这里存的是每个点-双连通分量里的点(如果要存边需要修改) if (bccno[x.v] != cnt) bcc[cnt].push_back(x.v), bccno[x.v] = cnt; if (x.u == u && x.v == v) break; } } } } vis[u] = 2; } void find_bcc(int n) { memset(vis, 0, sizeof(vis)); memset(bccno, 0, sizeof(bccno)); while(!s.empty()) s.pop(); cnt = 0; for (int i = 1; i <= n; i++) if (!vis[i]) dfs(i, -1, 0); } int mp[maxn][maxn], odd[maxn], color[maxn]; bool bipartite(int u, int id) { for (int i = 0; i < g[u].size(); i++) { int v = g[u][i]; if (bccno[v] != id) continue; if (color[u] == color[v]) return false; if (!color[v]) { color[v] = 3 - color[u]; if (!bipartite(v, id)) return false; } } return true; } int main () { while(~scanf("%d%d", &n, &m), n || m) { for (int i = 0; i <= n; i++) { g[i].clear(); for (int j = 0; j <= n; j++) mp[i][j] = 0; } int u, v; while(m--) { scanf("%d%d", &u, &v); mp[u][v] = mp[v][u] = 1; } for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) if (!mp[i][j]) g[i].pb(j), g[j].pb(i); find_bcc(n); memset(odd, 0, sizeof(odd)); for (int i = 1; i <= cnt; i++) { memset(color, 0, sizeof(color)); for (int j = 0; j < bcc[i].size(); j++) bccno[bcc[i][j]] = i; //因为割点的序号无意义,所以需要重新标号 int u = bcc[i][0]; color[u] = 1; if (!bipartite(u, i)) for (int j = 0; j < bcc[i].size(); j++) odd[bcc[i][j]] = 1; } int ans = n; for (int i = 1; i <= n; i++) if (odd[i]) ans--; printf("%d\n", ans); } return 0; }
POJ 2942 Knights of the Round Table (点-双连通分量 + 交叉法染色判二分图)
原文地址:http://blog.csdn.net/sio__five/article/details/38981653