杭电OJ_hdu2821_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 }
时间: 2024-08-04 09:15:44

杭电OJ_hdu2821_Pusher的相关文章

杭电 HDU 1164 Eddy&#39;s research I

Eddy's research I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7117    Accepted Submission(s): 4268 Problem Description Eddy's interest is very extensive, recently  he is interested in prime

hdu 1016 Prime Ring Problem DFS解法 纪念我在杭电的第一百题

Prime Ring Problem Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 29577    Accepted Submission(s): 13188 Problem Description A ring is compose of n circles as shown in diagram. Put natural num

杭电ACM分类

杭电ACM分类: 1001 整数求和 水题1002 C语言实验题——两个数比较 水题1003 1.2.3.4.5... 简单题1004 渊子赛马 排序+贪心的方法归并1005 Hero In Maze 广度搜索1006 Redraiment猜想 数论:容斥定理1007 童年生活二三事 递推题1008 University 简单hash1009 目标柏林 简单模拟题1010 Rails 模拟题(堆栈)1011 Box of Bricks 简单题1012 IMMEDIATE DECODABILITY

一个人的旅行 HDU杭电2066【dijkstra算法】

http://acm.hdu.edu.cn/showproblem.php?pid=2066 Problem Description 虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷路的人,汗~),但是草儿仍然很喜欢旅行,因为在旅途中 会遇见很多人(白马王子,^0^),很多事,还能丰富自己的阅历,还可以看美丽的风景--草儿想去很多地方,她想要去东京铁塔看夜景,去威尼斯看电影,去阳明山上看海芋,去纽约纯粹看雪景,去巴黎喝咖啡写信,去北京探望孟姜女--眼看寒假就快到了,这么一大段时间,可不

杭电1162--Eddy&#39;s picture(Prim()算法)

Eddy's picture Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 8070    Accepted Submission(s): 4084 Problem Description Eddy begins to like painting pictures recently ,he is sure of himself to b

杭电1276--士兵队列训练问题

士兵队列训练问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4605    Accepted Submission(s): 2148 Problem Description 某部队进行新兵队列训练,将新兵从一开始按顺序依次编号,并排成一行横队,训练的规则如下:从头开始一至二报数,凡报到二的出列,剩下的向小序号方向靠拢,再从头开始进行

杭电1272 并查集找环+判断连通

杭电1272 并查集找环+判断连通 E - E Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1272 Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该是双向连通的,就是说如果有一个通道连通了房间A和B

杭电ACM Java实现样例

若使用Java求解杭电ACM,答案提交必须注意两点: 1.类名一定得是Main,否则服务器无法编译: 2.必须用while进行输入判断. 以1000题测试题为例,代码如下: import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan=new Scanner(System.in); while(scan.hasNextInt()) { int a=scan.n

杭电 HDU 1038 Biker&#39;s Trip Odometer

Biker's Trip Odometer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4745    Accepted Submission(s): 3144 Problem Description Most bicycle speedometers work by using a Hall Effect sensor faste