poj2942 解题报告

本来想下午做完了周末好好玩,结果尼玛做了一晚上...

题意:

亚瑟王要在圆桌上召开骑士会议,为了不引发骑士之间的冲突,并且能够让会议的议题有令人满意的结果,每次开会前都必须对出席会议的骑士有如下要求:

1、 相互憎恨的两个骑士不能坐在直接相邻的2个位置;

2、 出席会议的骑士数必须是奇数,这是为了让投票表决议题时都能有结果。

如果出现有某些骑士无法出席所有会议(例如这个骑士憎恨所有的其他骑士),则亚瑟王为了世界和平会强制把他剔除出骑士团。

现在给定准备去开会的骑士数n,再给出m对憎恨对(表示某2个骑士之间使互相憎恨的),问亚瑟王至少要剔除多少个骑士才能顺利召开会议

( 我找网上的题意,自己说不清楚 )

题解:

1,将图求反,就是把有的边去掉,将没有的添上

2,找到双连通块

3,在双连通块中找是否存在奇圈,若存在则块中的骑士都可以开会的

4,统计有多少骑士不能存在在大于1的奇圈中的

代码:

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

const int MAXN = 1005 ;
const int MAXM = MAXN * MAXN * 2 ;

struct type
{
    int  end , next ;
} ;

type  edge[MAXM] ;
int   head[MAXN] , Count , mark[MAXN]    ;
int   low[MAXN]  , dfn[MAXN] , vis[MAXN] ;
int   map[MAXN][MAXN] , num[MAXN] , belone[MAXN]  ;
int   color[MAXN] ;

stack < int > Stack ;

void  addedge( int start , int end )
{
    edge[Count].end  = end         ;
    edge[Count].next = head[start] ;
    head[start]      = Count ++    ;
}

int  bfs( int cur , int from )
{
    memset( color , -1 , sizeof( color ) ) ;
    queue < int > q ;
    q.push( cur ) ;
    color[cur] = 0 ;
    while( !q.empty() )
    {
        int  temp = q.front() ;
        q.pop() ;
        for( int i = head[temp] ; i != -1 ; i = edge[i].next )
        {
            int end = edge[i].end ;
            if( belone[end] != from ) continue ;
            if( color[end] == 1 - color[temp] ) continue ;
            if( color[end] == -1 )
            {
                color[end] = 1 - color[temp] ;
                q.push( end ) ;
            }
            else if( color[end] == color[temp] ) return 1 ;
        }
    }
    return 0 ;
}

void  tarjan_dfs( int cur , int father , int & cnt , int & Time )
{
    Stack.push( cur ) ;
    dfn[cur] = low[cur] = Time ++ ;
    vis[cur] = 1 ;
    for( int i = head[cur] ; i != -1 ; i = edge[i].next )
    {
        int  end = edge[i].end ;
        if( end == father ) continue ;
        if( !vis[end] )
        {
            tarjan_dfs( end , cur , cnt , Time )  ;
            low[cur] = min( low[cur] , low[end] ) ;
            if( dfn[cur] <= low[end] )
            {
                int  temp , Cnt = 0 ;
                cnt ++ ;
                do
                {
                    temp = Stack.top() ;
                    Stack.pop() ;
                    num[Cnt] = temp ;
                    belone[temp] = cnt ;
                    Cnt ++ ;
                }while( temp != end ) ;
                num[Cnt] = cur ;
                belone[cur] = cnt ;
                Cnt ++ ;
                if( bfs( cur , cnt ) ){
                    for( int j = 0 ; j < Cnt ; j ++ ){
                        mark[num[j]] = 1 ;
                    }
                }
            }
        }
        else low[cur] = min( low[cur] , dfn[end] ) ;
    }
}

int   tarjan( int n )
{
    int  Time = 0 , cnt = 0 ;
    memset( dfn , 0 , sizeof( dfn ) ) ;
    memset( low , 0 , sizeof( low ) ) ;
    memset( vis , 0 , sizeof( vis ) ) ;
    memset( num , 0 , sizeof( num ) ) ;
    memset( belone , -1 , sizeof( belone ) ) ;
    for( int i = 1 ; i <= n ; i ++ ){
        if( !vis[i] ) tarjan_dfs( i , -1 , cnt , Time ) ;
    }
    return cnt ;
}

int  main()
{
    int  m , n , i , j ;
    int  start , end ;
    while( scanf( "%d%d" , & n , & m ) && n && m )
    {
        memset( head , -1 , sizeof( head ) ) ;
        memset( map  ,  0 , sizeof(  map ) ) ;
        memset( mark ,  0 , sizeof( mark ) ) ;
        Count = 0 ;
        while( m -- )
        {
            scanf( "%d%d" , & start , & end ) ;
            map[start][end] = 1 ;
            map[end][start] = 1 ;
        }
        for( i = 1 ; i <= n ; i ++ )
            for( j = 1 ; j <= n ; j ++ )
            {
                if( i == j ) continue ;
                if( !map[i][j] ) addedge( i , j ) ;
            }
        int  ans  = 0 ;
        int  temp = tarjan( n ) ;
        for( i = 1 ; i <= n ; i ++ )
            if( mark[i] == 0 ) ans ++ ;
        printf( "%d\n" , ans ) ;
    }
    return 0 ;
}


代码修修改改好多次才过的,所以很挫....

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值