/*
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