码迷,mamicode.com
首页 > 移动开发 > 详细

la3523 白书例题 圆桌骑士 双联通分量+二分图

时间:2015-03-01 23:43:30      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:

具体题解看大白书P316

技术分享
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <stack>
#include <cstdio>
using namespace std;
struct Edge{int u,v;};
const int maxn = 1000+10;
int pre[maxn],iscut[maxn],bccno[maxn],dfs_clock,bcc_cnt;
vector<int>G[maxn],bcc[maxn];
stack<Edge>S;
int dfs(int u, int fa){
    int lowu=pre[u]=++dfs_clock;
    int child=0;
    for(int i=0; i<G[u].size(); i++){
        int v=G[u][i];
        Edge e = (Edge){u,v};
        if(!pre[v]){ // v没有访问过
            S.push(e);
            child++;
            int lowv=dfs(v,u);
            lowu = min(lowu,lowv);// 用后代的 low函数更新自己
            if(lowv>=pre[u]){
                iscut[u]=true;
                bcc_cnt++; bcc[bcc_cnt].clear();
                for(;;){
                    Edge x = S.top(); S.pop();
                    if(bccno[x.u]!=bcc_cnt){
                         bcc[bcc_cnt].push_back(x.u);
                         bccno[x.u]=bcc_cnt;
                    }
                    if(bccno[x.v]!=bcc_cnt){
                         bcc[bcc_cnt].push_back(x.v);
                         bccno[x.v]=bcc_cnt;
                    }
                    if(x.u==u&&x.v==v) break;
                }
            }
        }
        else if(pre[v]<pre[u]&&v!=fa){
            S.push(e);
            lowu=min(lowu,pre[v]); // 用反向边更新自己
        }
    }
    if(fa<0&&child==1) iscut[u]=0;
    return lowu;
}
void find_bcc(int n){
    memset(pre,0,sizeof(pre));
    memset(iscut,0,sizeof(iscut));
    memset(bccno,0,sizeof(bccno));
    dfs_clock=bcc_cnt=0;
    for(int i=0 ; i<n ; i++)
        if(!pre[i]) dfs(i,-1);
}
int odd[maxn],color[maxn];
bool bipartite(int u, int b){
    for(int i=0; i<G[u].size(); ++i){
        int v=G[u][i];
        if(bccno[v]!=b) continue;
        if(color[u] == color[v]) return false;
        if(!color[v]){
             color[v]= 3- color[u];
             if(!bipartite(v,b)) return false;
        }
    }
     return true;
}
int A[maxn][maxn];
int main()
{
    int kase=0, n,m;
    while(scanf("%d%d",&n,&m)==2&&n){
        for(int i=0; i<n; i++) G[i].clear();
        memset(A,0,sizeof(A));
        for(int i=0; i<m; ++i){
             int u,v;
             scanf("%d%d",&u,&v);
             u--; v--;
             A[u][v]=A[v][u]=1;
        }
        for(int u=0; u<n; ++u)
             for(int v=u+1; v<n; ++v)
        if(!A[u][v]){
             G[u].push_back(v); G[v].push_back(u);
        }
        find_bcc(n);
        memset(odd,0,sizeof(odd));
        for(int i=1; i<=bcc_cnt; ++i){
             memset(color,0,sizeof(color));
             for(int j=0; j<bcc[i].size(); ++j)
                bccno[bcc[i][j]]=i;
             int u = bcc[i][0];
             color[u]=1;
             if(!bipartite(u,i))
                for(int j=0; j<bcc[i].size(); ++j)
                 odd[bcc[i][j]]=1;
        }
        int ans=n;
        for(int i=0; i<n; ++i)
             if(odd[i]) ans--;
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

la3523 白书例题 圆桌骑士 双联通分量+二分图

标签:

原文地址:http://www.cnblogs.com/Opaser/p/4307741.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!