被震惊到了!没想到图上的知识居然那么玄妙。
归纳出两点:
1.对于一个连通分量内,若二分图染色后为二分图,则图内全为偶环,无奇环。
2.对于一个连通分量内,若二分图染色后不为二分图,则图内全为奇环,无偶环。
证明我还是画一画图吧。
对于结论1。
先来个二分图
然后选择其中的一个偶环,
我们发现根据二分图的性质,从左道右就必定能够从右到左,那么这就不是个奇环了。
对于结论2。
我们发现在一个连通分量中,若能找到一个奇环,对于任意一个点连接图上任意两个点都一定能够都到包含着个点的一个奇环、一个偶环,易证。
所以说哈哈啦。
code实现也是很简单的。
一个二分图染色,一个Tarjan。
//随便贴一份代码吧。。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#define clr(x) memset((x),0,sizeof(x))
using namespace std;
const int N=1010;
const int M=1000010;
int n,m,i,j,k,l;
int head[N],next[M],list[M],tot,caset;
int dfn[N],low[N],sta[N],sta_tot,cnt__index,bfn[N],bfn_tot,col[N];
int aa[N][N],ans[N];
void add(int a,int b){
tot++;
list[tot]=b;
next[tot]=head[a];
head[a]=tot;
}
bool dfs(int x,int c){
col[x]=c;
for(int i=head[x];i;i=next[i])
if(bfn[list[i]]==bfn_tot){
if(col[list[i]]==c)return false;
else if(col[list[i]]!=(c^1)&&dfs(list[i],c^1)==false)return false;
}
return true;
}
void colour(int x){
ans[x]=1;bfn[x]=-1;
for(int i=head[x];i;i=next[i])
if(bfn[list[i]]==bfn_tot)colour(list[i]);
return;
}
int tarjan(int x,int fa){
int i,j,k;
dfn[x]=low[x]=++cnt__index;
sta[++sta_tot]=x;
for(int i=head[x];i;i=next[i])
if(i!=fa){
if(!dfn[list[i]]){
low[x]=min(low[x],tarjan(list[i],i^1));
if(low[list[i]]>=dfn[x]){
bfn_tot++;
while(sta[sta_tot+1]!=list[i])
bfn[sta[sta_tot--]]=bfn_tot;
bfn[sta[sta_tot]]=bfn_tot;
bfn[x]=bfn_tot;
if(!dfs(x,x<<1))colour(x);
}
}
else low[x]=min(low[x],dfn[list[i]]);
}
return low[x];
}
int main(){
while(scanf("%d%d",&n,&m),n||m){
tot=1;cnt__index=sta_tot=bfn_tot=0;
clr(ans),clr(col),clr(head),clr(bfn),clr(dfn);
caset++;
for(i=1;i<=m;i++){
scanf("%d%d",&j,&k);
aa[j][k]=caset;
aa[k][j]=caset;
}
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
if(aa[i][j]!=caset)
{add(i,j);add(j,i);}
for(i=1;i<=n;i++)
if(!dfn[i])tarjan(i,0);
k=0;
for(i=1;i<=n;i++)
if(!ans[i]||!head[i])k++;
printf("%d\n",k);
}
return 0;
}