【代码】POJ 2723

// 题目来源:POJ 2723
// 题目大意:m道门,每道门两把锁,有n对钥匙,对应2*n把锁,已知一对钥匙内取出一把另一把就会消失,求按顺序最多可开多少门
// 解决方法:依然2-sat啦,只不过要带上二分答案

#include <cstdio>
#include <string>
#define o 10002
#define _ 10002

void link( int, int );
bool check( int );
void tarjan( int );

int next[_], g[_];
int h[o], stack[o], opp[o], a[o], b[o], dfn[o], low[o], code[o];
int n, m, t, index, top, cnt;
bool ins[o];

int main( )
{
    freopen( "2723.in", "r", stdin );
    freopen( "2723.out", "w", stdout );
    scanf( "%d%d", &n, &m );
    int aa, bb;
    while( n != 0 )
    {
        memset( opp, 0, sizeof( opp ) );
        for( int i = 1; i <= n; i++ )
        {
            scanf( "%d%d", &aa, &bb );
            opp[aa] = bb;
            opp[bb] = aa;
        }
        for( int i = 1; i <= m; i++ )
            scanf( "%d%d", &a[i], &b[i] );
        int left = 0, right = m, mid = ( left + right ) / 2 + 1;
        while( right != left )
        {
            if( check( mid ) )
                left = mid;
            else
                right = mid - 1;
            mid = ( left + right ) / 2 + 1;
        }
        printf( "%d\n", left );
        scanf( "%d%d", &n, &m );
    }
    return 0;
}

void link( int aa, int bb )
{
    next[++t] = h[aa];
    h[aa] = t;
    g[t] = bb;
}

bool check( int m )
{
    if( m == 0 ) return 1;
    memset( next, 0, sizeof( next ) );
    memset( h, 0, sizeof( h ) );
    memset( dfn, 0, sizeof( dfn ) );
    memset( low, 0, sizeof( low ) );
    memset( code, 0, sizeof( code ) );
    t = index = 0;
    for( int i = 1; i <= m; i++ )
    {
        link( opp[ a[i] ], b[i] );
        link( opp[ b[i] ], a[i] );
    }
    for( int i = 0; i < 2*n; i++ )
        if( !dfn[i] ) tarjan( i );
    for( int i = 0; i < 2*n; i++ )
        if( code[i] == code[ opp[i] ] ) return 0;
    return 1;
}

void tarjan( int i )
{
    int j;
    dfn[i] = low[i] = ++index;
    stack[++top] = i;
    ins[i] = true;
    for( int k = h[i]; k; k = next[k] )
    {
        j = g[k];
        if( !dfn[j] )
        {
            tarjan( j );
            if( low[j] < low[i] ) low[i] = low[j];
        }
        else if( ins[j] && dfn[j] < low[i] )
            low[i] = dfn[j];
    }
    if( dfn[i] == low[i] )
    {
        cnt++;
        do
        {
            j = stack[top--];
            code[j] = cnt;
            ins[j] = false;
        }
        while( i != j );
    }
}

猜你喜欢

转载自blog.csdn.net/JarjingX/article/details/8518501
今日推荐