CCF I’m stuck!

梦里梦外; 2021-09-14 03:26 328阅读 0赞

一、试题

问题描述
  给定一个R行C列的地图,地图的每一个方格可能是’#’, ‘+’, ‘-‘, ‘|’, ‘.’, ‘S’, ‘T’七个字符中的一个,分别表示如下意思:
  ‘#’: 任何时候玩家都不能移动到此方格;
  ‘+’: 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非’#’方格移动一格;
  ‘-‘: 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非’#’方格移动一格;
  ‘|’: 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非’#’方格移动一格;
  ‘.’: 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为’#’,则玩家不能再移动;
  ‘S’: 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非’#’方格移动一格;
  ‘T’: 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非’#’方格移动一格。
  此外,玩家不能移动出地图。
  请找出满足下面两个性质的方格个数:
  1. 玩家可以从初始位置移动到此方格;
  2. 玩家不可以从此方格移动到目标位置。
输入格式
  输入的第一行包括两个整数R 和C,分别表示地图的行和列数。(1 ≤ R, C ≤ 50)。
  接下来的R行每行都包含C个字符。它们表示地图的格子。地图上恰好有一个’S’和一个’T’。
输出格式
  如果玩家在初始位置就已经不能到达终点了,就输出“I’m stuck!”(不含双引号)。否则的话,输出满足性质的方格的个数。
样例输入
5 5
–+-+
..|#.
..|##
S-+-T

.

样例输出
2
样例说明
  如果把满足性质的方格在地图上用’X’标记出来的话,地图如下所示:
  –+-+
  ..|#X
  ..|##
  S-+-T
  ####X

二、代码

直接从S点深搜,然后从T点深搜,比较取值。需要注意两种搜法区别。
代码来源

  1. #include <iostream>
  2. #include <memory.h>
  3. using namespace std;
  4. #define DIM 50
  5. int R,C;
  6. char G[DIM][DIM];
  7. bool sCanReach[DIM][DIM];//起点能到达的矩阵
  8. bool tCanReach[DIM][DIM];//终点能到的矩阵
  9. //正向深搜,从起点出发
  10. void ForwardDFS(bool sign[DIM][DIM], int curR, int curC){
  11. int Row = R, Col = C;
  12. //若 当前点已走过 或 当前点是障碍物,停止递归
  13. if (sign[curR][curC] || G[curR][curC] == '#')
  14. {
  15. return ;
  16. }
  17. //标记此点可达
  18. sign[curR][curC] = true;
  19. //标记可以往哪个方向移动
  20. bool up,down,left,right;
  21. up = down = left = right = false;
  22. if (G[curR][curC] == '.')//向下移动
  23. {
  24. down = true;
  25. }else if (G[curR][curC] == '-')//左右移动
  26. {
  27. left = right = true;
  28. }else if (G[curR][curC] == '|')//上下移动
  29. {
  30. up = down = true;
  31. }else if (G[curR][curC] == '+' || G[curR][curC] == 'S' || G[curR][curC] == 'T')//上下左右移动
  32. {
  33. up = down = left = right = true;
  34. }
  35. //上
  36. if (up && curR-1 >= 0)
  37. {
  38. ForwardDFS(sign,curR-1,curC);
  39. }
  40. //下
  41. if (down && curR+1 < Row)
  42. {
  43. ForwardDFS(sign,curR+1,curC);
  44. }
  45. //左
  46. if (left && curC-1 >= 0)
  47. {
  48. ForwardDFS(sign,curR,curC-1);
  49. }
  50. //右
  51. if (right && curC+1 < Col)
  52. {
  53. ForwardDFS(sign,curR,curC+1);
  54. }
  55. }
  56. //从终点出发,反向DFS
  57. // 反向搜索的方法不能跟之前正向一样,假设T上面一个-,按照正向那么是可以走通的,但是对于反向来说,从-显然不能走到下方的T。
  58. // 所以反向是从上一点试探性的向上下左右走一步到达下一点,然后以下一点为基准判断是否能走到上一点。
  59. void ReserveDFS(bool sign[DIM][DIM],int curR, int curC,/*当前点 */int preR, int preC /*上一个点*/)
  60. {
  61. int Row = R, Col = C;
  62. //若 当前点已走过 或 当前点是障碍物,停止递归
  63. if (sign[curR][curC] || G[curR][curC] == '#')
  64. {
  65. return ;
  66. }
  67. //从下面来的,可以返回去,其他方向来的无法原路返回
  68. if (G[curR][curC] == '.' && preR == curR+1 && preC == curC)
  69. {
  70. sign[curR][curC] = true;
  71. }else if (G[curR][curC] == '-' && preR == curR)
  72. {
  73. sign[curR][curC] = true;
  74. }else if (G[curR][curC] == '|' && preC == curC)
  75. {
  76. sign[curR][curC] = true;
  77. }else if (G[curR][curC] == 'S' || G[curR][curC] == '+' || G[curR][curC] == 'T')
  78. {
  79. sign[curR][curC] = true;
  80. }
  81. //没有方式可以从下一点走到上一点,那么无需再试探,直接返回
  82. if (sign[curR][curC] == false)
  83. {
  84. return ;
  85. }
  86. //上
  87. if (curR-1 >= 0)
  88. {
  89. ReserveDFS(sign,curR-1,curC,curR,curC);
  90. }
  91. //下
  92. if (curR+1 < Row)
  93. {
  94. ReserveDFS(sign,curR+1,curC,curR,curC);
  95. }
  96. //左
  97. if (curC-1 >= 0)
  98. {
  99. ReserveDFS(sign,curR,curC-1,curR,curC);
  100. }
  101. //右
  102. if (curC+1 < Col)
  103. {
  104. ReserveDFS(sign,curR,curC+1,curR,curC);
  105. }
  106. }
  107. int main()
  108. {
  109. memset(sCanReach, 0, sizeof(sCanReach));
  110. memset(tCanReach, 0, sizeof(tCanReach));
  111. cin>>R>>C;
  112. for (int i=0; i<R; i++)
  113. {
  114. for (int j=0; j<C; j++)
  115. {
  116. cin>>G[i][j];
  117. }
  118. }
  119. //处理
  120. for (int i=0; i<R; i++)
  121. {
  122. for (int j=0; j<C; j++)
  123. {
  124. if (G[i][j] == 'S')
  125. {
  126. ForwardDFS(sCanReach,i,j);
  127. }
  128. }
  129. }
  130. for (int i=0; i<R; i++)
  131. {
  132. for (int j=0; j<C; j++)
  133. {
  134. if (G[i][j] == 'T')
  135. {
  136. // 如果起点到终点都没有那么直接输出
  137. if (sCanReach[i][j] == false)
  138. {
  139. cout<<"I'm stuck!"<<endl;
  140. return 0;
  141. }
  142. ReserveDFS(tCanReach,i,j,i,j);
  143. }
  144. }
  145. }
  146. int num = 0;
  147. for (int i=0; i<R; i++)
  148. {
  149. for (int j=0; j<C; j++)
  150. {
  151. // 注意除去自身
  152. if (G[i][j] != 'S' && G[i][j] != 'T' &&
  153. sCanReach[i][j] && !tCanReach[i][j])
  154. {
  155. num++;
  156. }
  157. }
  158. }
  159. cout<<num<<endl;
  160. return 0;
  161. }

发表评论

表情:
评论列表 (有 0 条评论,328人围观)

还没有评论,来说两句吧...

相关阅读

    相关 ccf I’m stuck!

    试题名称: I’m stuck! 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述   给定一个R行C列的地图,地图的每一个方格可能是

    相关 IM 架构

    >  09年进入公司就开始研究openfire,做一款手机IM软件,经过3个月的不懈努力,产品终于上线了。上线初产品功能比较简单。上线初架构比较简单,服务器是单机,后来由于用户

    相关 IM

    尝试写个IM框架 [github][] TCP 请求响应模型 重连 心跳 解决拆包和粘包 自定义编解码 数据库 [github

    相关 CCF I’m stuck!

    一、试题 问题描述   给定一个R行C列的地图,地图的每一个方格可能是’\’, ‘+’, ‘-‘, ‘|’, ‘.’, ‘S’, ‘T’七个字符中的一个,分别表示如下