ZJU 3531 Alice Madness Return 【BFS HASH状态】

ZJU 3531 Alice Madness Return 【BFS HASH状态】

有一段日子木有更新solution神马的,北京区域赛的准备工作好烦哪。强烈要求出现一个组委会,而不是我们这帮集训队的来干各种奇葩活。

言归正传,9月的浙大月赛可搞题颇多,场上就想写这题,可惜木有机时,只能场下写咯。可惜一写就掉坑里了,直到现在才爬出来,好恶心的一道题啊。

题意:
10*10的棋盘,有一个你控制的棋子A,每步可四向移动;有一个镜像棋子B,和你呈镜像运动,遇边、石则当前回合不动;路上有石头,不可入;有压路机,循环运动,遇神杀神,遇石回头;地图上有<=5个宝石,你需要用A去拾取全部(WA点1,用A拾取,B没用);有两个出口,需要让A、B同时到达这俩出口,且拿满宝石,则你赢了。被压路机压到A、B或者同时到达出口时宝石没拿满,都是死。

做法:
就是BFS+模拟,模拟的规则略复杂。
先说状态,压路机方向 + 压路机位置 + A位置 + B位置 + 五块宝石的拿取状态。最后一个状态我用2^5来存,所以整体是一个9位数(虽说大牛们说前两个状态因为压路机的循环移动性质乘起来只有20种)。整体状态数=2 * 10 * 100 * 100 * 32 = 6400000 ,果断hash。一开始用MAP,TLE了;后来只能手写hash了,不仅要记hash之前的状态值还需要记对应状态的权值,难怪那么大内存。
接着就是模拟了:
每次解hash(注意hash数字时候的顺序)得取当前状态,然后算出下一回合A、B、压路机K的位置和宝石状态。
但是判定非法的时候,需要按顺序判断:
因为走的顺序是A、B、K,所以先判断A,check(超范围、碰R),碰K(未动),碰B,碰到则状态非法;再判断B,若碰新A,check,碰K,则不动。先不判K。
然后判断A是否拿到了新的宝石。
此时要判断A、B是否达到了出口,如果达到了而宝石不齐,则状态非法(wa点2);若齐了,则更新最短路长(不要在出队以后再更新,要在入队前更新,否则压路机会把这种情况给判非法掉)。只要达到出口,则状态不进队。
最后判K,吃了A或者B则状态非法。(WA点3)

代码写的好矬啊,别人800ms过,我wa+tle了两版才2400ms过。。。蒟蒻伤不起啊。

#include  < iostream >
#include 
< cstdio >
#include 
< cstring >
#include 
< map >
#include 
< queue >
#include 
< algorithm >
using   namespace  std;
#define  maxn 11
#define  hashsize (6400013)
#define  maxm (hashsize + 10)
int  ans;
const   int  inf  =   1   <<   30 ;
char  mst[maxn][maxn];
int  vis[maxm];
int  cas;
int  tot;
struct  HASH
{
    
int  x,step;
    HASH(){}
    HASH(
int  _x, int  _s):x(_x),step(_s){}
}h[maxm];
inline 
int  find( int  x)
{
    
int  z  =  x  %  hashsize;
    
return  vis[z]  ==  cas ? h[z].step: - 1 ;
}
inline 
void  insert( int  x, int  value)
{
    
int  z  =  x  %  hashsize;
    vis[z] 
=  cas;
    h[z] 
=  HASH(x,value);
}
inline 
void  update( int  x, int  value)
{
    
int  z  =  x  %  hashsize;
    h[z].step 
=  value;
}
struct  node
{
    
int  x,y;
    node(){}
    node(
int  a, int  b):x(a),y(b){}
    
bool   operator   == ( const  node p)
    {
        
return  x  ==  p.x  &&  y  ==  p.y;
    }
}pa,pb,en[
2 ],ki,pc[ 6 ];
int  r,c;
int  pcs;
char  dir;
int  dx[]  =  { - 1 , 1 , 0 , 0 };
int  dy[]  =  { 0 , 0 , - 1 , 1 };
char  rd[]  =  { ' N ' , ' S ' , ' W ' , ' E ' };
int  co( char  _d)
{
    
for ( int  i  =   0 ;i  <   4 ;i ++ )
        
if (rd[i]  ==  _d)
            
return  i;
}
int  hash( int  _d,node p[], bool  gd[])
{
    
int  x  =   0 ;
    
for ( int  i  =   0 ;i  <  pcs;i ++ )
        
if (gd[i])
            x 
|=  ( 1   <<  i);
    
int  idx  =   100 ;
    
for ( int  i  =   2 ;i  >=   0 ;i -- )
    {
        x 
+=  idx  *  p[i].x;
        idx 
*=   10 ;
        x 
+=  idx  *  p[i].y;
        idx 
*=   10 ;
    }
    x 
+=  (_d  +   1 *  idx;
    
return  x;
}
inline 
bool  check( int  x, int  y)
{
    
return   0   <=  x  &&  x  <  r  &&   0   <=  y  &&  y  <  c  &&  mst[x][y]  !=   ' R ' ;
}
void  bfs()
{
    queue 
< int >  Q;
    
bool  gd[ 6 ];
    
for ( int  i  =   0 ;i  <  pcs;i ++ )
        gd[i] 
=   true ;
    node p[
3 ];
    p[
0 =  ki;
    p[
1 =  pa;
    p[
2 =  pb;
    
int  s  =  hash(co(dir),p,gd);
    
// cout << s << endl;
     if (find(s)  ==   - 1 )
        insert(s,
0 );
    Q.push(s);
    
// cout << s << endl;
     while ( ! Q.empty())
    {
        
int  now  =  Q.front();
        Q.pop();
        
// cout << now << endl;
         int  step  =  find(now);
        
int  idx  =   100000000 ;
        
int  tdir  =  now  /  idx  -   1 ;
        now 
-=  (tdir + 1 *  idx;
        idx 
/=   10 ;
        
// cout << now << endl;
         for ( int  i  =   0 ;i  <   3 ;i ++ )
        {
            p[i].y 
=  now  /  idx;
            now 
-=  p[i].y  *  idx;
            idx 
/=   10 ;
            p[i].x 
=  now  /  idx;
            now 
-=  p[i].x  *  idx;
            idx 
/=   10 ;
        }
        
// cout << now << endl;
         int  x,y;
        x 
=  p[ 0 ].x  +  dx[tdir];
        y 
=  p[ 0 ].y  +  dy[tdir];
        
if ( ! check(x,y))
        {
            x 
=  p[ 0 ].x;
            y 
=  p[ 0 ].y;
            tdir 
^=   1 ;
        }
        node tk 
=  node(x,y);
        
for ( int  i  =   0 ;i  <   4 ;i ++ )
        {
            
bool  dg[ 6 =  { 0 };
            
int  ax  =  p[ 1 ].x  +  dx[i],ay  =  p[ 1 ].y  +  dy[i];
            
int  bx  =  p[ 2 ].x  +  dx[i ^ 1 ],by  =  p[ 2 ].y  +  dy[i ^ 1 ];
            
if ( ! check(ax,ay)  ||   node(ax,ay)  ==  p[ 0 ||  node(ax,ay)  ==  p[ 2 ]) // they can stay in the same point???
                 continue ;
            
if ( ! check(bx,by)  ||  node(bx,by)  ==  p[ 0 ||  node(bx,by)  ==  node(ax,ay))
            {
                bx 
=  p[ 2 ].x;
                by 
=  p[ 2 ].y;
            }
            
int  what  =   0 ;
            
for ( int  j  =   0 ;j  <  pcs;j ++ )
                
if (((now  >>  j)  &   1 &&   ! (node(ax,ay)  ==  pc[j]))
                {    
                    dg[j] 
=   1 ;
                    what 
|=   1   <<  j;
                }
            node q[
3 ];
            q[
0 =  tk;
            q[
1 =  node(ax,ay);
            q[
2 =  node(bx,by);
            
int  ano  =  step  +   1 ;
            
if ((en[ 0 ==  q[ 1 &&  en[ 1 ==  q[ 2 ])  ||  (en[ 0 ==  q[ 2 &&  en[ 1 ==  q[ 1 ]))
            {
                
if (what  ==   0 )
                    ans 
=  min(ano,ans);
                
else
                    
continue ;
            }
            
if (q[ 0 ==  q[ 1 ||  q[ 0 ==  q[ 2 ])
                
continue ;
            
int  temp  =  hash(tdir,q,dg);
            
int  comp  =  find(temp);
            
if (comp  ==   - 1   ||  comp  >  ano)
            {
                
if (comp  ==   - 1 )
                    insert(temp,ano);
                
else
                    update(temp,ano);
                Q.push(temp);
            }
        }
    }
    printf(
" %d\n " ,ans  ==  inf ?- 1 :ans);
}
int  main()
{
    cas 
=   0 ;
    
while (scanf( " %d %d " , & r, & c)  ==   2 )
    {
        cas
++ ;
        
int  end  =   0 ;
        pcs 
=   0 ;
        tot 
=   0 ;
        
for ( int  i  =   0 ;i  <  r;i ++ )
            
for ( int  j  =   0 ;j  <  c;j ++ )
            {
                
char  opt;
                scanf(
"  %c " , & opt);
                mst[i][j] 
=  opt;
                
switch (opt)
                {
                    
case   ' A ' :
                        pa 
=  node(i,j);
                        
break ;
                    
case   ' B ' :
                        pb 
=  node(i,j);
                        
break ;
                    
case   ' K ' :
                        ki 
=  node(i,j);
                        
break ;
                    
case   ' E ' :
                        en[end
++ =  node(i,j);
                        
break ;
                    
case   ' M ' :
                        pc[pcs
++ =  node(i,j);
                        
break ;
                }
            }
        ans 
=  inf;
        scanf(
"  %c " , & dir);
        bfs();
    }
}
å
backward sentence

你可能感兴趣的:(ZJU 3531 Alice Madness Return 【BFS HASH状态】)