转化模型为在求一个无向图中不属于任何简单奇圈的点的个数,我们可以求出所有属于简单奇圈的点剩下的点就是答案,首先求在一个简单圈中的点,显然是求点双连通分量(俩个点的点双连通分量不是简单圈,但在后面判断二分图时会把这种情况排除掉),二分图与不存在奇圈的图是等价定义,所以只要在求出点双连通分量后判断每个连通分量是否是二分图(因为如果子原图是二分图,那么其子图必定也是二分图,所以只要判断连通分量是不是二分图就可以了).
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::istringstream; using std::make_pair; using std::greater; using std::endl; const int MAXN(1010); const int MAXE(2000010); struct EDGE { int u, v; int next; }; int first[MAXN], rear; EDGE edge[MAXE]; void init() { memset(first, -1, sizeof(first)); rear = 0; } void insert(int tu, int tv) { edge[rear].u = tu; edge[rear].v = tv; edge[rear].next = first[tu]; first[tu] = rear++; } int pre[MAXN], low[MAXN], bccno[MAXN]; bool is_cut[MAXN]; stack<int> st; vector<int> bcc[MAXN]; int dfs_clock, bcc_cnt; //接着在不经过桥的情况下dfs求出所有双强连通分量即可 //在求解点和边的连通分量时,连接到自己的边都没有意义 int dfs(int cur, int fa) { pre[cur] = low[cur] = ++dfs_clock; int child(0); for(int i = first[cur]; i != -1; i = edge[i].next) { int tv = edge[i].v; if(!pre[tv]) { ++child; st.push(i); int lowv = dfs(tv, cur); low[cur] = min(low[cur], lowv); if(lowv >= pre[cur]) { is_cut[cur] = true; ++bcc_cnt; bcc[bcc_cnt].clear(); int temp; while(true) { temp = st.top(); st.pop(); if(bccno[edge[temp].u] != bcc_cnt) { bccno[edge[temp].u] = bcc_cnt; bcc[bcc_cnt].push_back(edge[temp].u); } if(bccno[edge[temp].v] != bcc_cnt) { bccno[edge[temp].v] = bcc_cnt; bcc[bcc_cnt].push_back(edge[temp].v); } if(temp == i) break; } } } else if(pre[tv] < pre[cur] && tv != fa) { st.push(i); low[cur] = min(low[cur], pre[edge[i].v]); } } if(fa == -1 && child > 1) is_cut[cur] = true; return low[cur]; } void find_bcc(int n) { dfs_clock = bcc_cnt = 0; memset(pre, 0, sizeof(pre)); memset(low, 0, sizeof(low)); memset(bccno, 0, sizeof(bccno)); memset(is_cut, 0, sizeof(is_cut)); for(int i = 1; i <= n; ++i) if(!pre[i]) dfs(i, -1); } int color[MAXN]; bool isbipartite(int cur, int no) { for(int i = first[cur]; i != -1; i = edge[i].next) { int tv = edge[i].v; if(bccno[tv] == no) { if(!color[tv]) { color[tv] = 3-color[cur]; if(!isbipartite(tv, no)) return false; } else if(color[tv] == color[cur]) return false; } } return true; } bool odd[MAXN]; bool hate[MAXN][MAXN]; int main() { int n, m; while(scanf("%d%d", &n, &m), n+m) { init(); memset(hate, 0, sizeof(hate)); int tu, tv; for(int i = 0; i < m; ++i) { scanf("%d%d", &tu, &tv); hate[tu][tv] = true; hate[tv][tu] = true; } for(int i = 1; i <= n; ++i) for(int j = i+1; j <= n; ++j) if(!hate[i][j]) { insert(i, j); insert(j, i); } find_bcc(n); memset(odd, 0, sizeof(odd)); for(int i = 1; i <= bcc_cnt; ++i) { memset(color, 0, sizeof(color)); for(int j = 0; j < bcc[i].size(); ++j) bccno[bcc[i][j]] = i; int cur = bcc[i][0]; color[cur] = 1; if(!isbipartite(cur, i)) for(int j = 0; j < bcc[i].size(); ++j) odd[bcc[i][j]] = true; } int ans = 0; for(int i = 1; i <= n; ++i) if(!odd[i]) ++ans; printf("%d\n", ans); } return 0; }