zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    Kafka设计解析(二)- Kafka High Availability (上)
    Kafka设计解析(三)- Kafka High Availability (下)
    Kafka深度解析
    Cloudera Manager(CDH5)内部结构、功能包括配置文件、目录位置等
    Failed to start /etc/rc.d/rc.local Compatibility
    Offset Management For Apache Kafka With Apache Spark Streaming
    maven-assembly-plugin打包可执行的jar包
    How Cigna Tuned Its Spark Streaming App for Real-time Processing with Apache Kafka
    SystemTap Beginners Guide
    数据可视化的开源方案: Superset vs Redash vs Metabase (二)
  • 原文地址:https://www.cnblogs.com/yongqiang/p/5656207.html
Copyright © 2011-2022 走看看