Poj 2942 点双联通分量

王桂平的图论书上把这题错误地归类为边双联通分量,于是WA到生活不能自理。主要区别在于这样的图:

这里写图片描述

显然按照每个点经过一次的环来算的话,这个图并不能构成环,所以每个点经过一次的环应该包含于点双联通分量内部。
而每条边经过一次的环包含于边双联通分量内部。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct edge{
    int to,next;
}e[2000003];
bool used[2000003];
bool vis[1003];
int head[1003];
int cnt,tmpdfn;
int dfn[1003];
int low[1003];
int color[1003];
int bcc[1003];
int stk[1003];
bool odd[1003];
bool g[1003][1003];
int ans,n,m,bcc_cnt,top;
bool flag;
void add(int u,int v){
    e[cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void init(){
    cnt=tmpdfn=ans=bcc_cnt=0;
    memset(g,false,sizeof(g));
    memset(vis,false,sizeof(vis));
    memset(used,false,sizeof(used));
    memset(head,-1,sizeof(head));
    memset(bcc,0,sizeof(bcc));
    memset(odd,false,sizeof(odd));
}
bool draw(int u,int c){
    color[u]=c;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(bcc[v]!=bcc_cnt)continue;
        if(color[v]==-1){
            if(!draw(v,c^1))return false;
        }
        else if(color[v]==color[u])return false;
    }
    return true;
}
void dfs(int u){
    vis[u]=true;
    dfn[u]=++tmpdfn;
    low[u]=dfn[u];
    stk[++top]=u;
    for(int i=head[u];~i;i=e[i].next){
        if(used[i])continue;
        used[i]=used[i^1]=true;
        int v=e[i].to;
        if(vis[v]){
            low[u]=min(low[u],dfn[v]);
        }
        else {
            dfs(v);
            low[u]=min(low[u],low[v]);
            if(low[v]>=dfn[u]){
                ++bcc_cnt;
                while(1){
                    int x=stk[top--];
                    bcc[x]=bcc_cnt;
                    if(x==v)break;
                }
                bcc[u]=bcc_cnt;
                memset(color,-1,sizeof(color));
                if(!draw(u,0)){
                    for(int j=1;j<=n;j++)if(bcc[j]==bcc_cnt)odd[j]=true;
                }
            }
        }
    }
}
int main(){
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0)break;
        init();
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            g[u][v]=g[v][u]=true;
        }
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                if(!g[i][j]){
                    add(i,j);
                    add(j,i);
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(!vis[i])dfs(i);
        }
        for(int i=1;i<=n;i++){
            if(!odd[i])ans++;
        }
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/MrBird_to_fly/article/details/80239242