【代码】POJ 2749

// 题目来源:POJ 2749
// 题目大意:有两点坐标已知,现要在坐标系上各点与两点之一建立路径,已知某些点不能建立在同一个点上,有些点必须建立在同一个点上,求最小曼哈顿距离
// 解决方法:枚举最大值,然后用2-sat判断可行性

#include <cstdio>
#include <cstdlib>
#include <string>
#define o 10000
#define _ 1000000
#define oo 100000000
using namespace std;

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

int next[_], g[_], a[_], b[_], c[_], d[_];
int h[o], code[o], dfn[o], low[o], stack[o], x[o], y[o];
int n, m, sx1, sy1, sx2, sy2, t, top, cnt, index, dis, sa, sb;
bool ins[o];

int main( )
{
    freopen( "2749.in", "r", stdin );
    freopen( "2749.out", "w", stdout );
    scanf( "%d%d%d%d%d%d%d", &n, &sa, &sb, &sx1, &sy1, &sx2, &sy2 );
    dis = abs( sx1 -sx2 ) + abs( sy1 - sy2 );
    for( int i = 1; i <= n; i++ )
        scanf( "%d%d", &x[i], &y[i] );
    for( int i = 1; i <= sa; i++ )
        scanf( "%d%d", &a[i], &b[i] );
    for( int i = 1; i <= sb; i++ )
        scanf( "%d%d", &c[i], &d[i] );
    int left = 0, right = oo, mid = ( left + right ) / 2;
    while( left != right )
    {
        if( check( mid ) )
            right = mid;
        else
            left = mid + 1;
        mid = ( left + right ) / 2;
    }
    if( left == oo )
        printf( "-1" );
    else
        printf( "%d", left );
    return 0;
}

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

bool check( int limit )
{
    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 = cnt = 0;
    for( int i = 1; i <= sa; i++ )
    {
        link( a[i], b[i]+n );
        link( b[i], a[i]+n );
        link( a[i]+n, b[i] );
        link( b[i]+n, a[i] );
    }
    for( int i = 1; i <= sb; i++ )
    {
        link( c[i], d[i] );
        link( d[i], c[i] );
        link( c[i]+n, d[i]+n );
        link( d[i]+n, c[i]+n );
    }
    for( int i = 1; i <= n; i++ )
        for( int j = i + 1; j <= n; j++ )
        {
            if( abs( x[i]-sx1 )+abs( x[j]-sx1 )+abs( y[i]-sy1 )+abs( y[j]-sy1 ) > limit )
            {
                link( i, j+n );
                link( j, i+n );
            }
            if( abs( x[i]-sx1 )+abs( x[j]-sx2 )+abs( y[i]-sy1 )+abs( y[j]-sy2 )+dis > limit )
            {
                link( i, j );
                link( j+n, i+n );
            }
            if( abs( x[i]-sx2 )+abs( x[j]-sx1 )+abs( y[i]-sy2 )+abs( y[j]-sy1 )+dis > limit )
            {
                link( i+n, j+n );
                link( j, i );
            }
            if( abs( x[i]-sx2 )+abs( x[j]-sx2 )+abs( y[i]-sy2 )+abs( y[j]-sy2 ) > limit )
            {
                link( i+n, j );
                link( j+n, i );
            }
        }
    for( int i = 1; i <= 2*n; i++ )
        if( !dfn[i] ) tarjan( i );
    for( int i = 1; i <= n; i++ )
        if( code[i] == code[i+n] )
            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 );
    }
}

你可能感兴趣的:(poj,2-sat,2749)