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\n%d\n", 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("\n"); 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 }