正文

Zoj 2279 In the Mirror2008-02-13 18:21:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/niao0311/32646.html

分享到:

一道很好的搜索题。WA一次,原因是二进制hash开的太小。

一般求最短步数的问题,大多采用BFS,当终点与当前节点的XY值相等时输出,本题也不例外。难点在于,镜子的状态如何处理。

注意到镜子的数目<10,每一镜子仅有两种状态 \ 和/ 。因此将每一面镜子左右视为0与1,得到二进制编码的值hash,存入BFS中的节点。最大节点状态为2^10*10*10=102400 ,时间和空间上完全满足要求。

这里总共有三个102400的数组。一个队列Q,一个step存放某节点的步数,一个sight进行预处理,记录下当镜子出于某种状态hash下,每个点是否能够访问。

代码太长,格式放不上来,辛辛苦苦打了半天没了,只好帖原文。里面有一些相当有用的技巧,比如对于每一面镜子i的开关操作(0置为1,1置为0)是2^i xor hash,又比如对方向的处理数组与处理函数——这就和马路边的城管一样,常见,而且实用。但是方向函数看代码是看不懂的,需要自己分析一下。

#include <cstdio>
#include <string>

char a[11][11];
int N, M, num_m, num_b, step[10][10][1024], sight[10][10][1024], ans;
int dir[4][2] =
{
 { 0, 1 }, { 1, 0 }, { 0, -1 }, { - 1, 0 }
};
int p[11] =
{
 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024
};

typedef struct
{
 int x, y, dir, step, h;
} Bat;
Bat sb, eb, Mirror[12], Q[102410], B[100];

int init ();
void bfs ();
void proc ( int );
int redir ( int, int, int );  //计算方向
void print ();

int main ()
{
 //freopen ( "in.txt", "r", stdin );
 while ( init () )
 {
  bfs ();
  print ();
 }
 return 0;
}

int init ()
{
 num_m = num_b = 0, ans = -1;
 if ( scanf ( "%d%d", &N, &M ) == EOF )
 {
  return 0;
 }
 gets ( a[0] );
 int i, j; 
 for ( i = 0; i < N; i ++ )
 {
  gets ( a[i] );
  for ( j = 0; j < M; j ++ )
  {
   //终始点
   if ( a[i][j] == 'S' )
   {
    sb.x = i, sb.y = j, a[i][j] = '.';
   }
   if ( a[i][j] == 'E' )
   {
    eb.x = i, eb.y = j, a[i][j] = '.';
   }
   //镜子
   if ( a[i][j] == '/' )
   {
    Mirror[num_m].x = i, Mirror[num_m].y = j, Mirror[num_m ++].dir = 0;
   }
   if ( a[i][j] == '\\' )
   {
    Mirror[num_m].x = i, Mirror[num_m].y = j, Mirror[num_m ++].dir = 1;
   }
   //蝙蝠
   if ( a[i][j] == '>' )
   {
    B[num_b].x = i, B[num_b].y = j, B[num_b ++].dir = 0;
   }
   if ( a[i][j] == 'v' )
   {
    B[num_b].x = i, B[num_b].y = j, B[num_b ++].dir = 1;
   }
   if ( a[i][j] == '<' )
   {
    B[num_b].x = i, B[num_b].y = j, B[num_b ++].dir = 2;
   }
   if ( a[i][j] == '^' )
   {
    B[num_b].x = i, B[num_b].y = j, B[num_b ++].dir = 3;
   }
  }
 }
 //printf ( "%d %d\n", num_b, num_m );
 memset ( step, 0xff, sizeof ( step ) );
 memset ( sight, 0xff, sizeof ( sight ) );
 return 1;
}

void bfs ()
{
 //预处理所有的镜面反射状况
 int hash = 0, i, j, k, tx, ty, td;
 for ( i = 0; i < num_m; i ++ )
 {
  hash += Mirror[i].dir ? p[i] : 0;
 }
 step[sb.x][sb.y][hash] = 0;
 //保存初始值
 for ( k = 0; k < p[num_m]; k ++ )
 {
  proc ( k );
  //处理镜面 p[num_m]种情况
  for ( i = 0; i < N; i ++ )
  {
   for ( j = 0; j < M; j ++ )
   {
    if ( a[i][j] != '.' )
    {
     sight[i][j][k] = 0;
    }
   }
  }
  for ( i = 0; i < num_b; i ++ )
  {
   tx = B[i].x, ty = B[i].y, td = B[i].dir;
   tx += dir[td][0], ty += dir[td][1];
   while ( tx >= 0 && tx < N && ty >= 0 && ty < M && a[tx][ty] != '#' )
   {
    sight[tx][ty][k] = 0;
    td = redir ( tx, ty, td );
    tx += dir[td][0], ty += dir[td][1];
   }
  }
  //pt ( k );
 }
 //BFS
 int op, ed, tstep, th; 
 proc ( hash );
 step[sb.x][sb.y][hash] = 0;
 if ( sight[sb.x][sb.y][hash] == 0 )
  return;
 for ( op = -1, ed = 0, Q[0].x = sb.x, Q[0].y = sb.y, Q[0].step = 0, Q[0].h = hash; op ++ < ed; )
 {
  if ( Q[op].x == eb.x && Q[op].y == eb.y )
  {
   ans = Q[op].step;
   break;
  }
  tstep = Q[op].step + 1, th = Q[op].h;
  for ( i = 0; i < 4; i ++ )
  {
   tx = Q[op].x + dir[i][0], ty = Q[op].y + dir[i][1];
   if ( tx >= 0 && tx < N && ty >= 0 && ty < M && sight[tx][ty][th] )
   {
    if ( step[tx][ty][th] == -1 )
    {
     step[tx][ty][th] = tstep;
     Q[++ ed].x = tx, Q[ed].y = ty, Q[ed].h = th, Q[ed].step = tstep;
    }
   }
  }
  for ( i = 0; i < num_m; i ++ )
  {
   th = Q[op].h ^ p[i], tx = Q[op].x, ty = Q[op].y;
   if ( sight[tx][ty][th] && step[tx][ty][th] == -1 )
   {
    step[tx][ty][th] = tstep;
    Q[++ ed].x = tx, Q[ed].y = ty, Q[ed].h = th, Q[ed].step = tstep;
   }
  }
 }
}

void proc ( int hash )
{
 int i;
 int x = hash;
 for ( i = 0; i < num_m; i ++ )
 {
  Mirror[i].dir = hash & 1;
  //printf ( "%d", Mirror[i].dir );
  a[Mirror[i].x][Mirror[i].y] = Mirror[i].dir ? '\\' : '/';
  hash >>= 1;
 }
 //pt ( x );
}

int redir ( int x, int y, int d )
{
 if ( a[x][y] == '/' )
 {
  return 3 - d;
 }
 if ( a[x][y] == '\\' )
 {
  return d ^ 1;
 }
 return d;
}

void print ()
{
 if ( ans == -1 )
 {
  printf ( "poor\n" );
 }
 else
 {
  printf ( "%d\n", ans );
 }
}

 

阅读(2991) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册