收获:
1、面对在图中分离出一个圈的问题时,要想到用无向图的边双连通分量
2、当强调这个圈满足边数的奇偶条件时,要想到和二分图有关
#pragma warning(disable:4786)
#pragma comment(linker, "/stk:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#include<bitset>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 1e3 + 5;
struct Edge{
int u,v;
Edge(int u=0,int v=0):u(u),v(v){}
}edges[maxn * maxn * 2];
int tot;
int n , m , stamp , dfn[maxn] , low[maxn] , iscut[maxn] , bccno[maxn] ;
vector<int> vec[maxn] , bcc[maxn];
int scnt , bcc_cnt , stk[maxn * maxn * 2] , hate[maxn][maxn] , vis[maxn] , color[maxn];
void Add_Edge(int u , int v)
{
Edge e = Edge(u , v);
edges[tot] = e;
vec[u].push_back(tot);
++tot;
}
void init()
{
mem(dfn , 0); mem(low , 0);
mem(iscut , 0); mem(bccno , 0);
mem(hate , 0); mem(vis , 0);
for(int i = 1 ; i <= n ; i++){
vec[i].clear();
bcc[i].clear();
}
stamp = scnt = bcc_cnt = tot = 0;
}
bool bipartite(int u)
{
for(int i = 0 ; i < vec[u].size() ; i++){
int v = edges[vec[u][i]].v;
if(bccno[v] != bcc_cnt) continue;
if(color[v] == color[u]) return false;
if(!color[v]){
color[v] = 3 - color[u];
if(!bipartite(v)) return false;
}
}
return true;
}
void tarjan(int index , int fa)
{
int child = 0 ;
dfn[index] = low[index] = ++stamp;
for(int i = 0 ; i < vec[index].size() ; i++){
int tmp = edges[vec[index][i]].v;
if(!dfn[tmp]){
stk[++scnt] = vec[index][i];
tarjan(tmp , index);
low[index] = min(low[index] , low[tmp]);
if(low[tmp] >= dfn[index]){
iscut[index] = 1;
bcc[++bcc_cnt].clear();
while(1){
int num = stk[scnt--];
if(bccno[edges[num].u] != bcc_cnt){
bcc[bcc_cnt].push_back(edges[num].u);
bccno[edges[num].u] = bcc_cnt;
}
if(bccno[edges[num].v ] != bcc_cnt){
bcc[bcc_cnt].push_back(edges[num].v);
bccno[edges[num].v] = bcc_cnt;
}
if(edges[num].u == index && edges[num].v == tmp){
break;
}
}
mem(color , 0);
color[index] = 1;
if(!bipartite(index)){
for(int k = 0 ; k < bcc[bcc_cnt].size() ; k++){
int cur = bcc[bcc_cnt][k];
vis[cur] = 1;
}
}
}
}
else if(dfn[tmp] < dfn[index] && fa != tmp){
stk[++scnt] = vec[index][i];
low[index] = min(low[index] , dfn[tmp]);
}
}
if(fa == -1 && child == 1)
iscut[index] = 0;
}
int main()
{
int k1 , k2;
while(scanf("%d %d" , &n , &m) != EOF){
if(!n && !m) break;
init();
for(int i = 1 ; i <= m ; i++){
scanf("%d %d" , &k1 , &k2);
hate[k1][k2] = hate[k2][k1] = 1;
}
for(int i = 1 ; i <= n; i++){
for(int j = 1 ; j <= n ; j++){
if(hate[i][j] || i == j) continue;
Add_Edge(i , j);
}
}
for(int i = 1 ; i <= n ; i++){
if(!dfn[i]) tarjan(i , -1);
}
int ans = n;
for(int i = 1 ; i <= n ; i++){
if(vis[i]) --ans;
}
printf("%d\n",ans);
}
return 0;
}