BZOJ4290 传送门

昨天考试考了这道题,学校评测不开O2被卡的一愣一愣的。

这种题线性复杂度就线性复杂度,为什么要卡常数。

顺便提一句,GRH大爷O(m*n*ans)的算法有90分,我的O(m*n)算法75。(万恶的STL)

这是什么烂数据(只是吐槽我们学校的数据,与BZOJ无关)

那我们来讲一讲做法:(首先,这是一道SB题)

我们考虑传送的行为:

1.如果一个传送门被穿越,那么从此以后进的那个门一定不用回去,出的那个门可以在出去以后立即打一枪替换。所以从此这两个门都不用进了

2.如果我们从一个传送门出来,那么我们一定有一个时刻枪可以打到传送门所在位置。

3.我们考虑这个位置:打完这一枪以后,在哪里开传送门并不重要,都可以到达。那么我们就贪心地走到最近的一面墙就可以了(这一步等价于建立一条从这个点到所有枪可以到达的点建立了一条长度为t+1的边(t为当前点到最近的贴墙空地的距离)

下面是代码:

/**************************************************************
    Problem: 4290
    User: CYZ
    Language: C++
    Result: Accepted
    Time:2444 ms
    Memory:81668 kb
****************************************************************/
 
#include<cstdio>
#include<queue>
#include<list>
using namespace std ; 
 
const int MAXR = 1000 + 20 ;
int C , R ;
char M [ MAXR ] [ MAXR ] ;
int dis1 [ MAXR ] [ MAXR ] ; 
int dis2 [ MAXR ] [ MAXR ] ;
bool vis [ MAXR ] [ MAXR ] ;
int s1 [ MAXR ] [ MAXR ] ; 
int s2 [ MAXR ] [ MAXR ] ; 
int s3 [ MAXR ] [ MAXR ] ; 
int s4 [ MAXR ] [ MAXR ] ; 
 
queue < pair < int , int > > q ;
queue < pair < int , int > , list < pair < int , int > > > Q [ 1000 * 1000 + 20 ] ;
int cx , cy ;
int ans = -1 ;
 
void P ( const int x , const int y ) {
    if ( x < 0 || x > C + 1 || y < 0 || y > R + 1 || dis1 [ x ] [ y ] != 0 ) return ;
    dis1 [ x ] [ y ] = 1 ; 
    q . push ( make_pair ( x , y ) ) ;
}
 
template < class T1 , class T2 > 
void min_equal ( T1 & a , const T2 & b ) {
    if ( a > b ) a = b ;
}
 
template < class T1 , class T2 >
void max_equal ( T1 & a , const T2 & b ) {
    if ( a < b ) a = b ;
}
 
int main () {
    /*
    freopen ( "portals.in" , "r" , stdin ) ;
    freopen ( "portals.out" , "w" , stdout ) ;
    */
    scanf ( "%d%d" , & R , & C ) ;
    for ( int x = 1 ; x <= R ; ++ x ) scanf ( "%s" , M [ x ] + 1 ) ;
    for ( int x = 0 ; x <= R + 1 ; ++ x ) M [ x ] [ 0 ] = M [ x ] [ C + 1 ] = '#' ;
    for ( int y = 0 ; y <= C + 1 ; ++ y ) M [ 0 ] [ y ] = M [ R + 1 ] [ y ] = '#' ;
    for ( int x = 1 ; x <= R ; ++ x ) 
        for ( int y = 1 ; y <= C ; ++ y ) {
            dis2 [ x ] [ y ] = 10000000 ;
            if ( M [ x ] [ y ] == 'S' ) {
                Q [ 0 ] . push ( make_pair ( x , y ) ) ; 
            } else if ( M [ x ] [ y ] == 'C' ) {
                cx = x ; 
                cy = y ; 
            }
        }
    for ( int x = 0 ; x <= R + 1 ; ++ x ) 
        for ( int y = 0 ; y <= C + 1 ; ++ y ) 
        dis1 [ x ] [ y ] = M [ x ] [ y ] == '#' ;
    for ( int x = 0 ; x <= R + 1 ; ++ x ) 
        for ( int y = 0 ; y <= C + 1 ; ++ y ) 
        if ( M [ x ] [ y ] == '#' ) {
            P ( x + 1 , y ) ;
            P ( x - 1 , y ) ; 
            P ( x , y - 1 ) ; 
            P ( x , y + 1 ) ; 
        }
    while ( ! q . empty () ) {
        const int x = q . front () . first ; 
        const int y = q . front () . second ;
        q . pop () ; 
        if ( dis1 [ x + 1 ] [ y ] == 0 ) {
            dis1 [ x + 1 ] [ y ] = dis1 [ x ] [ y ] + 1 ; 
            q . push ( make_pair ( x + 1 , y ) ) ;
        }
        if ( dis1 [ x - 1 ] [ y ] == 0 ) {
            dis1 [ x - 1 ] [ y ] = dis1 [ x ] [ y ] + 1 ; 
            q . push ( make_pair ( x - 1 , y ) ) ;
        }
        if ( dis1 [ x ] [ y + 1 ] == 0 ) {
            dis1 [ x ] [ y + 1 ] = dis1 [ x ] [ y ] + 1 ; 
            q . push ( make_pair ( x , y + 1 ) ) ;
        } 
        if ( dis1 [ x ] [ y - 1 ] == 0 ) {
            dis1 [ x ] [ y - 1 ] = dis1 [ x ] [ y ] + 1 ; 
            q . push ( make_pair ( x , y - 1 ) ) ;
        } 
    }
    for ( int x = 1 ; x <= R ; ++ x ) 
        for ( int y = 1 ; y <= C ; ++ y ) {
            dis2 [ x ] [ y ] = -1 ;
            if ( s1 [ x ] [ y ] == 0 ) 
            for ( int x2 = x ; M [ x2 ] [ y ] != '#' ; ++ x2 ) 
                s1 [ x2 ] [ y ] = x ; 
            if ( s3 [ x ] [ y ] == 0 ) 
            for ( int y2 = y ; M [ x ] [ y2 ] != '#' ; ++ y2 ) 
                s3 [ x ] [ y2 ] = y ; 
        }
    for ( int x = R ; x >= 1 ; -- x ) 
        for ( int y = C ; y >= 1 ; -- y ) {
            if ( s2 [ x ] [ y ] == 0 ) 
            for ( int x2 = x ; M [ x2 ] [ y ] != '#' ; -- x2 ) 
                s2 [ x2 ] [ y ] = x ; 
            if ( s4 [ x ] [ y ] == 0 ) 
            for ( int y2 = y ; M [ x ] [ y2 ] != '#' ; -- y2 ) 
                s4 [ x ] [ y2 ] = y ;
        }
    for ( int t = 0 ; ans == -1 ; ++ t ) {
        queue < pair < int , int > , 
              list < pair < int , int > > > & q = Q [ t ] ;  
        while ( ! q . empty () ) {
            const int x = q . front () . first ; 
            const int y = q . front () . second ;
            q . pop () ; 
            if ( vis [ x ] [ y ] ) continue ;
            vis [ x ] [ y ] = true ;
            dis2 [ x ] [ y ] = t ;
            if ( x == cx && y == cy ) {
                ans = t ;
                break ;
            }
            if ( M [ x + 1 ] [ y ] != '#' && ! vis [ x + 1 ] [ y ] ) 
                Q [ t + 1 ] . push ( make_pair ( x + 1 , y ) ) ;
            if ( M [ x - 1 ] [ y ] != '#' && ! vis [ x - 1 ] [ y ] ) 
                Q [ t + 1 ] . push ( make_pair ( x - 1 , y ) ) ;
            if ( M [ x ] [ y + 1 ] != '#' && ! vis [ x ] [ y + 1 ] ) 
                Q [ t + 1 ] . push ( make_pair ( x , y + 1 ) ) ; 
            if ( M [ x ] [ y - 1 ] != '#' && ! vis [ x ] [ y - 1 ] ) 
                Q [ t + 1 ] . push ( make_pair ( x , y - 1 ) ) ;
            if ( ! vis [ s1 [ x ] [ y ] ] [ y ] ) Q [ t + dis1 [ x ] [ y ] ] . push 
                ( make_pair ( s1 [ x ] [ y ] , y ) ) ; 
            if ( ! vis [ s2 [ x ] [ y ] ] [ y ] ) Q [ t + dis1 [ x ] [ y ] ] . push 
                ( make_pair ( s2 [ x ] [ y ] , y ) ) ;
            if ( ! vis [ x ] [ s3 [ x ] [ y ] ] ) Q [ t + dis1 [ x ] [ y ] ] . 
                push ( make_pair ( x , s3 [ x ] [ y ] ) ) ;
            Q [ t + dis1 [ x ] [ y ] ] . 
                push ( make_pair ( x , s4 [ x ] [ y ] ) ) ; 
        }
    }
    /*
    for ( int x = 1 ; x <= R ; ++ x ) {
        for ( int y = 1 ; y <= C ; ++ y ) printf ( "%2d " , dis2 [ x ] [ y ] ) ;
        putchar ( '\n' ) ;
    }*/
    printf ( "%d\n" , ans ) ;
    return 0 ;
}

 

转载于:https://www.cnblogs.com/Christopher-Cao/p/5426473.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值