hdu 2821 Pusher

题目大意:

  在http://www.hacker.org/push网站上,有一个名字叫PusherBoy的游戏。这个游戏给出一个R * C的棋盘,棋盘上有许多堆阻碍前进的箱子。游戏的胜利条件是通过推箱子的方式,清除掉棋盘上所有的箱子。

  现在你需要选择一块空旷的区域作为PusherBoy的初始位置,然后选择一个方向(U代表向上,D代表向下,L代表向左,R代表向右)来推箱子。一旦你选好了一个方向,PusherBoy将一直向前走直到碰到箱子才停下来(不能走出棋盘),然后他从这堆箱子中移除一个箱子(当然咯,如果这一堆中只有一个箱子,移除这个箱子,那么这个地方就清理干净了),同时将剩下的这堆箱子移动到相邻位子。(如果相邻位置也有一堆箱子,那么这两堆箱子将组合成一个新的堆,其数量为前面两堆箱子数量之和)

  不过请注意,如果有堆箱子紧贴着PusherBoy,那么PusherBoy是无法推动它的。也就是说推动箱子的前提是在PusherBoy和箱子之间必须要有一个空隙。举个栗子,看下面的图片。PusherBoy可以向上走,但是不能向下走。(圆圈表示Pusher,正方形表示一堆箱子,嵌套的正方形表示这一堆有两个箱子)如果一堆箱子被推出边界,那么这堆箱子就被认为清理干净了。

                                              

输入:

  每个输入中都有几个测试用例。每一个测试用例的前面两行包各包含一个整数,分别是C和R(R,C <= 25)接着是R行,表示这个棋盘。‘.’表示一个空旷的区域,小写字母表示一堆箱子(‘a’表示一个箱子,‘b’表示两个箱子,‘c’表示三个箱子,以此类推)

输出:

  每个测试用例需要输出三行。前面的两行各包含一个数,分别是x,y表示PusherBoy开始的位置。(0 <= x < R, 0 <= y < C)第三行包含PusherBoy清除所有箱子的移动序列,这个序列由‘U’,‘D’,‘L’,‘R’。任何正确的答案都将通过OJ测试。(Special Judge)

编程的时候需要注意的地方:

1、搜索开始的地方必须是'.'

2、搜索时,需要一个栈结构记录方向;打印结果的时候需要按照队列先进先出的原则输出方向。那么就需要用到双端队列这种数据结构,搜索的时候对队尾进行操作,打印结果的时候对队首进行操作。

3、需要重点注意的题目条件:(1)箱子被推出边界,就表示箱子被完全清理干净,而不是减去其中一个箱子。(2)PusherBoy与Blocks之间需要有'.',这样PusherBoy才能推动,否则不能推动。

4、保存好之前的状态(例如:用变量记录这堆箱子的字母以及与它相邻箱子的字母,总箱子数),方便后面的回溯。

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <stdlib.h>
  4 #include <deque>
  5 using namespace std;
  6 
  7 const int N = 30;
  8 const int dir[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };//移动的方向 0:上,1;下,2:左,3:右
  9 char board[N][N]; //记录棋盘
 10 int row, col;     //行、列
 11 int blocks;       //记录需要消除的箱子数量
 12 deque<int> result;//用双端队列记录移动方向(搜索的时候,需要一个栈结构管理,输出的时候需要一个队列管理)
 13 
 14 /* 每一个测试,先初始化数据 */
 15 void init(void)
 16 {
 17     blocks = 0;
 18 }
 19 
 20 /* 输入数据 */
 21 void inputBoard(void)
 22 {
 23     for (int i = 0; i < row; ++i)
 24     {
 25         scanf("%s", board[i]);
 26         for (int j = 0; j < col; ++j) //统计需要消灭多少箱子,搜索的时候当箱子数目为0时,表示找到一个结果
 27             if ('.' != board[i][j])
 28                 blocks += board[i][j] - 'a' + 1;
 29     }
 30 }
 31 
 32 /* 判断是否越界 */
 33 inline bool inBoard(int r, int c)
 34 {
 35     return 0 <= r && r < row && 0 <= c && c < col;
 36 }
 37 
 38 /* dfs搜索 */
 39 bool dfs(int r, int c)
 40 {
 41     if (0 == blocks) //board等于0比表示已经清理干净
 42         return true;
 43     for (int i = 0; i < 4; ++i)//上下左右四个方向移动
 44     {
 45         int _r = r + dir[i][0];//向dir[i]方向走第一步
 46         int _c = c + dir[i][1];
 47 
 48         if (false == inBoard(_r, _c)) continue;
 49         if ('.' != board[_r][_c]) continue;//向该方向走的第一步必须是'.'
 50 
 51         result.push_back(i);//记录移动的方向
 52         while (true == inBoard(_r, _c))//沿着该方向走,不能走出边界
 53         {
 54             if ('a' <= board[_r][_c] && board[_r][_c] <= 'z')//碰到字母才处理,否则一直向这个方向走
 55             {
 56 
 57                 int _rr = _r + dir[i][0];//碰到字母后,判断字母相邻位置(_rr, _cc)的情况
 58                 int _cc = _c + dir[i][1];
 59                 char b1 = board[_r][_c]; //记录(_r,_c),(_rr,_cc)的值,回溯的时候还原现场
 60                 char b2 = board[_rr][_cc];
 61 
 62                 if ('a' != board[_r][_c])//(_r,_c)位置为非'a'字母,表明字母降级并移动到相邻位置上。如果为a字母,则箱子直接消失了。
 63                 {
 64                     if (false == inBoard(_rr, _cc))//(_rr,_cc)在边界外边,那么blocks直接推干净
 65                     {
 66                         blocks -= (board[_r][_c] - 'a');
 67                     }
 68                     else if ('a' <= board[_rr][_cc] && board[_rr][_cc] <= 'z')//(_rr,_cc)也为 blocks,那么需要合并
 69                     {
 70                         char tmp = board[_r][_c] - 'a' + board[_rr][_cc];//合并两个blocks,组成一个更大的blokcs
 71                         if (tmp > 'z')
 72                             break; //组成的blocks超过'z'表明这种推法不可取
 73                         else
 74                             board[_rr][_cc] = tmp;
 75                     }
 76                     else //(_r,_c)相邻位置的为 '.'
 77                     {
 78                         board[_rr][_cc] = board[_r][_c] - 1;
 79                     }
 80                 }
 81                 board[_r][_c] = '.';//把(_r,_c)的位置变成 '.'
 82                 --blocks;
 83                 if (true == dfs(_r, _c)) return true;
 84                 ++blocks;
 85                 board[_r][_c] = b1;
 86                 if (true == inBoard(_rr, _cc))
 87                 {
 88                     board[_rr][_cc] = b2;
 89                 }
 90                 else
 91                 {
 92                     blocks += (board[_r][_c] - 'a');
 93                 }
 94                 break;//推blocks失败后,这条路走不通了,要回到原来的位子,换个方向走
 95             }
 96             _r += dir[i][0];
 97             _c += dir[i][1];
 98         }
 99         result.pop_back();
100     }
101     return false;
102 }
103 
104 bool dfsTravel( int &i, int &j )
105 {
106     for (i = 0; i < row; ++i)
107         for (j = 0; j < col; ++j)
108             if ('.' == board[i][j] && true == dfs(i, j))
109                 return true;
110     return false;
111 }
112 
113 /* 输出结果 */
114 void outputResult(int i, int j)
115 {
116     printf("%d
%d
", i, j);
117     while (!result.empty())
118     {
119         int tmp = result.front();
120         switch (tmp)
121         {
122         case 0: printf("U"); break;
123         case 1: printf("D"); break;
124         case 2: printf("L"); break;
125         case 3: printf("R"); break;
126         default: break;
127         }
128         result.pop_front();
129     }
130     printf("
");
131 }
132 
133 int main(void)
134 {
135     int i,j;
136     while (scanf("%d", &col) != EOF)
137     {
138         scanf("%d", &row);
139         init();
140         inputBoard();
141         if ( true == dfsTravel(i, j) )
142             outputResult(i, j);
143     }
144     return 0;
145 }
原文地址:https://www.cnblogs.com/yongqiang/p/5656207.html