poj2942 求v-DCC,二分图判奇环,补图

/*
给定一张无向图,求有多少点不被任何奇环包含
推论1:如果两个点属于两个不同的v-DCC,则他们不可能在同一个奇环内
推论2:某个v-DCC中有奇环,则这个v-DCC中所有点必定被属于某个奇环
只要求出补图中的所有v-DCC,判定每个v-DCC中是否存在奇环即可
如果某个v-DCC中包含奇环,则该联通块的所有点都被标记位1
最后只要求未被标记的点数量即可
*/
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define maxn 1005
int mp[maxn][maxn];
struct Edge{int to,nxt;}edge[];
int head[maxn],tot,n,m; void addedge(int u,int v){
edge[tot].to=v;edge[tot].nxt=head[u];head[u]=tot++;
} int ind,top,low[maxn],dfn[maxn],stack[maxn],flag[maxn],color[maxn],tmp[maxn],cnt;
int ok[maxn];//判断i是否在联通分量里
int dfs(int x,int col){//不能成功染色就返回0
color[x]=col;
for(int i=head[x];i!=-;i=edge[i].nxt){
int y=edge[i].to;
if(ok[y]==)continue;
if(color[y]!=-){//已经被染色过的点
if(color[y]==col)
return false;
continue;
}
if(!dfs(y,col^))
return false;
}
return true;
}
void Tarjan(int x){
dfn[x]=low[x]=++ind;
stack[++top]=x;
for(int i=head[x];i!=-;i=edge[i].nxt){
int y=edge[i].to;
if(!dfn[y]){
Tarjan(y);
low[x]=min(low[x],low[y]);
if(dfn[x]<=low[y]){//找到一个点双联通分量
int z;
cnt=;
memset(ok,,sizeof ok);
do{
z=stack[top--];
tmp[++cnt]=z;
ok[z]=;
}while(z!=y);
tmp[++cnt]=x;
//tmp数组中存点双联通分量
//开始判定奇环
memset(color,-,sizeof color);
ok[x]=;
if(!dfs(x,)){//如果v_DCC中有奇环
flag[x]=;
while(cnt--)
flag[tmp[cnt]]=;
}
}
}
else low[x]=min(low[x],dfn[y]);
}
}
void init(){
tot=ind=top=;
memset(head,-,sizeof head);
memset(low,,sizeof low);
memset(dfn,,sizeof dfn);
memset(flag,,sizeof flag);
memset(mp,,sizeof mp);
}
int main(){
while(cin>>n>>m,n){
init();
int u,v;
while(m--){
scanf("%d%d",&u,&v);
mp[u][v]=mp[v][u]=;
}
//建立补图
for(int i=;i<n;i++)
for(int j=i+;j<=n;j++)
if(mp[i][j]==)
addedge(i,j),addedge(j,i);
for(int i=;i<=n;i++)
if(dfn[i]==)
Tarjan(i);
int ans=n;
for(int i=;i<=n;i++)
if(flag[i])ans--;
cout<<ans<<endl;
}
}
上一篇:(Problem 36)Double-base palindromes


下一篇:DISK 100% BUSY,谁造成的?(ok)