http://poj.org/problem?id=2942

题意 :n个骑士举行圆桌会议,每次会议应至少3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置。如果意见发生分歧,则需要举手表决,因此参加会议的骑士数目必须是奇数,以防止赞同和反对的票一样多,知道哪些骑士相互憎恨之后,你的任务是统计有多少个骑士不可能参加任何一个会议。

思路 :这个题牵扯的知识点挺多的,具体的可以参考白书上解释的蛮详细的。

#include <iostream>
#include <stdio.h>
#include <stack>
#include <string.h>
#include <algorithm>
#include <vector>

using namespace std;
const int maxn = 1100 ;

struct Edge
{
    int u,v ;
    Edge(int u ,int v):u(u),v(v) {}
} ;

int pre[maxn],dfs_clock ,iscut[maxn],Bcc_cnt,Bccno[maxn] ;
vector<int>G[maxn],Bcc[maxn] ;
stack<Edge>S ;
int odd[maxn],color[maxn] ;
int A[maxn][maxn] ;

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])
        {
            S.push(e) ;
            child++ ;
            int lowv = dfs(v,u) ;
            lowu = min(lowu,lowv) ;
            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) ;
}

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

 

posted on 2014-02-10 16:59  枫、  阅读(199)  评论(0编辑  收藏  举报