【tarjan求双连通分量+染色判二分图】POJ 2942

这题debug的好郁闷啊!!!先是染色有问题,然后就是各种小错误....

判奇圈可以用二分图标准,因为奇圈肯定不是二分图,之前还要分离各双连通分量.......染色法判二分图一定要先对分量里每一个点都染一次色再枚举任意两个相邻的点看是否有同色,就是因为这里wa了n次!!!

#define N 1005
vector<int> v[N];
vector<int> lin[N];
int dfn[N],low[N];
bool instack[N],iscut[N];
int num_rt;
int cnt;
int step;
stack<int> sta;
bool g[N][N];
void init(int n){
    for(int i=0;i<=n;i++){
        instack[i] = 0;
        iscut[i] = 0;
        dfn[i] = 0;
        low[i] = 0;
    }
    step = 0;
    cnt = 0;
    while(!sta.empty())sta.pop();
}
void tarjan(int u,int fa){
    low[u] = dfn[u] = ++step;
    sta.push(u);
    instack[u] = 1;
    int i;
    for(i=0;i<v[u].size();i++){
        int to = v[u][i];
        if(to==fa)continue;
        if(!dfn[to]){
            tarjan(to,u);
            low[u] = min(low[u],low[to]);
            if(low[to]>=dfn[u]){
                if(fa==-1)num_rt++;
                else iscut[u] = 1;
                while(1){
                    int tmp = sta.top();
                    sta.pop();
                    iscut[tmp] = 0;
                    instack[tmp] = 0;
                    lin[cnt].push_back(tmp);
                    if(tmp==to)break;
                }
                lin[cnt].push_back(u);
                cnt++;
            }
        } else if(instack[to]) low[u] = min(low[u],dfn[to]);
    }
}
int col[N];
bool dfs(int id,int u,int c){
    int i;
    col[u] = c;
    for(i=0;i<lin[id].size();i++){
        int to = lin[id][i];
        if(u==to || col[to]!=-1)continue;
        if(g[u][to]){
            dfs(id,to,c^1);
        }
    }
    return true;
}
bool ok[N];
int solve(int n){
    int i,j;
    for(i=1;i<=n;i++){
        if(!dfn[i]){
            num_rt = 0;
            tarjan(i,-1);
            if(num_rt>=2){
                iscut[i] = 1;
            }
        }
    }
    int ans = 0;
    memset(ok,false,sizeof(ok));
    bool tag = 0;
    for(i=0;i<cnt;i++){
        for(j=0;j<=n;j++)col[j]=-1;
        int sz = lin[i].size();
        dfs(i,lin[i][0],1);
        bool tag = 0;
        for(j=0;j<sz;j++){
            for(int k=0;k<sz;k++){
                int a = lin[i][j],b = lin[i][k];
                if(a!=b && g[a][b] && col[a]==col[b]){
                    tag = 1;
                    break;
                }
            }
            if(tag)break;
        }
        if(tag){
            for(j=0;j<sz;j++){
                ok[lin[i][j]] = 1;
            }
        }
    }
    for(i=1;i<=n;i++){
        if(!ok[i])ans++;
    }
    return ans;
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m) &&(n+m)){
        int i,j;
        memset(g,true,sizeof(g));
        init(n);
        while(m--){
            int x,y;
            scanf("%d%d",&x,&y);
            g[x][y] = g[y][x] = false;
        }
        for(i=0;i<=n;i++){
            v[i].clear();
            lin[i].clear();
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=n;j++){
                if(g[i][j] && i!=j){
                    v[i].push_back(j);
                }
            }
        }
        printf("%d\n",solve(n));
    }
    return 0;
}



















  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值