码迷,mamicode.com
首页 > 其他好文 > 详细

UVALive-3523 Knights of the Round Table (双连通分量+二分图匹配)

时间:2015-10-21 00:01:55      阅读:286      评论:0      收藏:0      [点我收藏+]

标签:

题目大意:有n个骑士要在圆桌上开会,但是相互憎恶的两个骑士不能相邻,现在已知骑士们之间的憎恶关系,问有几个骑士一定不能参加会议。参会骑士至少有3个且有奇数个。

题目分析:在可以相邻的骑士之间连一条无向边,构成一张图G。则问题变成了有几个节点不在奇圈(有奇数个节点的圈)内,并且一个点在圈内最多出现一次。如果G不连通,应该对每一个分量分别求解。奇圈上的点一定在同一个双连通分量内,要找出所有的双连通分量。但是能构成二分图的双连通分量中一定没有奇圈,不能构成二分图的双连通分量中一定含有奇圈,并且分量中所有的点都在奇圈上,所有还要判断每一个双连通分量能不能构成二分图。

 

其实就是一道模板题。。。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<vector>
# include<stack>
# include<cstring>
# include<algorithm>
using namespace std;

const int maxn=1005;
struct Edge
{
    int u,v;
    Edge(int _u,int _v):u(_u),v(_v){}
};
stack<Edge>S;
vector<int>G[maxn],bcc[maxn];
int bcc_cnt,dfs_cnt,low[maxn],pre[maxn],odd[maxn],color[maxn],bccno[maxn],iscut[maxn],A[maxn][maxn];

int dfs(int u,int fa)
{
    int lowu=pre[u]=++dfs_cnt;
    int child=0;
    for(int i=0;i<G[u].size();++i){
        int v=G[u][i];
        if(!pre[v]){
            S.push(Edge(u,v));
            ++child;
            int lowv=dfs(v,u);
            lowu=min(lowu,lowv);
            if(lowv>=pre[u]){
                iscut[u]=1;
                bcc[++bcc_cnt].clear();
                while(1)
                {
                    Edge x=S.top();
                    S.pop();
                    if(x.u!=bcc_cnt){
                        bcc[bcc_cnt].push_back(x.u);
                        bccno[x.u]=bcc_cnt;
                    }
                    if(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(Edge(u,v));
            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_cnt=bcc_cnt=0;
    for(int i=0;i<n;++i)
        if(!pre[i])
            dfs(i,-1);
}

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[v]==color[u])
            return false;
        if(!color[v]){
            color[v]=3-color[u];
            if(!bipartite(v,b))
                return false;
        }
    }
    return true;
}

int main()
{
    int n,m,a,b;
    while(scanf("%d%d",&n,&m)&&(n+m))
    {
        memset(A,0,sizeof(A));
        for(int i=0;i<n;++i)  G[i].clear();
        while(m--){
            scanf("%d%d",&a,&b);
            --a,--b;
            A[a][b]=A[b][a]=1;
        }
        for(int i=0;i<n;++i)
            for(int j=i+1;j<n;++j)
                if(!A[i][j])
                    G[i].push_back(j),G[j].push_back(i);

        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;
}

  

UVALive-3523 Knights of the Round Table (双连通分量+二分图匹配)

标签:

原文地址:http://www.cnblogs.com/20143605--pcx/p/4896301.html

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