• 推箱子问题


    一 问题描述

    你站在一个由方格组成的二维度迷宫中,这些格子可能被填满岩石,也可能没被填满岩石。你可以一步一个格子地往北、往南、往东或往西移动。这样的动作叫作“走”。其中一个空单元格包含一个箱子,你可以站在箱子旁边,推动箱子到相邻的自由单元格。这样的动作叫作“推”。箱子除了用推的方式,不能移动,如果你把它推到角落里,就再也不能把它从角落里拿出来了。将其中一个空单元格标记为目标单元格。你的工作是通过一系列走和推把箱子带到目标格子里。由于箱子很重,所以要尽量减少推动的次数。编写程序,计算最后的移动顺序。

    二 输入和输出

    1 输入

    数据包含多个测试用例。每个测试用例的第 1 行都包含两个整数 r 和 c,表示迷宫的行数和列数。接下来是 r 行,每行 c 个字符,每个字符都描述迷宫中的一个格子,对被填满岩石的格子用“#”表示,对空格用“.”表示,对起始位置用“S”表示,对箱子的起始位置用“B”表示,对目标单元格用“T”表示。输入端以两个 0 终止。

    2 输出

    对于输入中的每个迷宫,都首先输出迷宫的编号。如果无法将箱子带到目标单元格里,则输出“Impossible”,否则输出一个最小推动次数的序列。如果多个这样的序列,则请选择一个最小总移动(走和推)次数的序列。如果仍然有多个这样的序列,则任务一个都可被接受。将序列输出为由 N、S、E、W、n、s、e 和 w 组成的字符串,大写表示推,小写表示走,祖母分别表示北、南、东和西这 4 个方向。在每个测试用例之后都输出一个空行。

    三 输入和输出样例

    1 输入样例

    1 7

    SB....T

    1 7

    SB..#.T

    7 11

    ###########

    #T##......#

    #.#.#..####

    #....B....#

    #.######..#

    #.....S...#

    ###########

    8 4

    ....

    .##.

    .#..

    .#..

    .#.B

    .##S

    ....

    ###T

    0 0

    2 输出样例

    Maze #1

    EEEEE

    Maze #2

    Impossible.

    Maze #3

    eennwwWWWWeeeeeesswwwwwwwnNN

    Maze #4

    swwwnnnnnneeesssSSS

    四 分析

    本问题是推箱子问题,要求先保证推箱子的次数最少,在此基础上再让人走的步数最少。推箱子时,人只有站在箱子反方向的前一个位置,才可以将箱子推向下一个位置。因此在移动箱子时,不仅需要判断新位置有没有岩石,还需要判断人是否可以到达反方向的前一个位置,在两者均有效时,才会让人移动。

    先求解箱子到目标位置的最短路径(BFS1),在推箱子的过程中,每推一步,都根据推的方向和箱子的位置得到箱子的前一个位置,再求解人到达这个位置的最短路径(BFS2)。在 BFS1 里面嵌套 BFS2 ,属于嵌套广度优先搜索。

    五 算法设计

    1 定义一个标识数组 vis[][],并将其初始化为 0,标识所有位置都未被访问。

    2 创建一个队列 q 维护箱子的状态,将人的初始位置 (sx,sy)、箱子的初始位置(bx,by)和初始路径(“”)入队,标记箱子的位置 vis[bx][by]=1。

    3 如果队列不空,则队头 now 出队,否则返回 false。

    4 从箱子的当前位置开始,向北、南、东、西这 4 个方向扩展。

    得到箱子的新位置:nbx=now.bx+dir[i][0];nby=now.by+dir[i][1]。

    得到箱子的前一个位置:tx=now.bx-dir[i][0];nby=now.by-dir[i][1]。

    如果这两个位置有效,则执行 BFS2 搜素人到达箱子的前一个位置(tx,ty)的最短路径,并记录路径 path。如果 BFS2 搜素成功,则判断是否到达目标,如果是,则返回答案 ans=now.path+path+dpath[i];否则标记箱子的新位置被访问 vis[nbx][nby]=1,将人的新位置(now.bx,now.by)、箱子的新位置(nbx,nby)和已走过的路径(now.path+path+dpathB[i]) 入队。

    5 转向步骤 3

    六 代码

    1. package com.platform.modules.alg.alglib.poj1475;
    2. import java.util.LinkedList;
    3. import java.util.Queue;
    4. public class Poj1475 {
    5. public String output = "";
    6. private int N;
    7. private int M;
    8. char mp[][] = new char[25][25];
    9. // 人和箱子的初始位置
    10. private int sx;
    11. private int sy;
    12. private int bx;
    13. private int by;
    14. private final int dir[][] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
    15. private final char dpathB[] = {'N', 'S', 'E', 'W'};
    16. private final char dpathP[] = {'n', 's', 'e', 'w'};
    17. private String ans;
    18. public String cal(String input) {
    19. String[] line = input.split("\n");
    20. String[] words = line[0].split(" ");
    21. N = Integer.parseInt(words[0]);
    22. M = Integer.parseInt(words[1]);
    23. for (int i = 0; i < N; i++) {
    24. String mapLine = line[i + 1];
    25. for (int j = 0; j < mapLine.length(); j++) {
    26. mp[i][j] = mapLine.charAt(j);
    27. if (mp[i][j] == 'S') {
    28. sx = i;
    29. sy = j;
    30. }
    31. if (mp[i][j] == 'B') {
    32. bx = i;
    33. by = j;
    34. }
    35. }
    36. }
    37. if (bfs())
    38. output += ans;
    39. else
    40. output += "Impossible";
    41. return output;
    42. }
    43. boolean check(int x, int y) {
    44. if (x < 0 || x >= N || y < 0 || y >= M) return false;
    45. if (mp[x][y] == '#') return false;
    46. return true;
    47. }
    48. boolean bfs() {
    49. int vis[][] = new int[25][25];
    50. vis[bx][by] = 1;
    51. Queue q = new LinkedList<>(); // 创建一个普通队列(先进先出)
    52. q.add(new node(sx, sy, bx, by, ""));
    53. while (!q.isEmpty()) {
    54. node now = q.peek();
    55. q.poll();
    56. for (int i = 0; i < 4; i++) {
    57. // 箱子的新位置
    58. int nbx = now.bx + dir[i][0];
    59. int nby = now.by + dir[i][1];
    60. // 箱子的前一个位置,人必须能到达这个位置
    61. int tx = now.bx - dir[i][0];
    62. int ty = now.by - dir[i][1];
    63. String path = "";
    64. StringBuilder pathBuilder = new StringBuilder(path);
    65. if (check(nbx, nby) && check(tx, ty) && vis[nbx][nby] == 0) {
    66. if (bfs2(now.px, now.py, now.bx, now.by, tx, ty, pathBuilder)) {
    67. if (mp[nbx][nby] == 'T') {
    68. ans = now.path + path + dpathB[i];
    69. return true;
    70. }
    71. vis[nbx][nby] = 1;
    72. q.add(new node(now.bx, now.by, nbx, nby, now.path + pathBuilder.toString() + dpathB[i]));
    73. }
    74. }
    75. }
    76. }
    77. return false;
    78. }
    79. boolean bfs2(int ppx, int ppy, int bbx, int bby, int tx, int ty, StringBuilder pathBuilder) {
    80. // 局部标识数组,不要定义全局
    81. int vis[][] = new int[25][25];
    82. vis[ppx][ppy] = 1; // 人的位置
    83. vis[bbx][bby] = 1; // 箱子的位置
    84. Queue Q = new LinkedList<>(); // 创建一个普通队列(先进先出)
    85. Q.add(new person(ppx, ppy, ""));
    86. while (!Q.isEmpty()) {
    87. person now = Q.peek();
    88. Q.poll();
    89. if (now.x == tx && now.y == ty) { // 目标位置,即箱子的前一个位置
    90. pathBuilder.append(now.path);
    91. return true;
    92. }
    93. for (int i = 0; i < 4; i++) {
    94. // 人的新位置
    95. int npx = now.x + dir[i][0];
    96. int npy = now.y + dir[i][1];
    97. if (check(npx, npy) && vis[npx][npy] == 0) {
    98. vis[npx][npy] = 1;
    99. Q.add(new person(npx, npy, now.path + dpathP[i]));
    100. }
    101. }
    102. }
    103. return false;
    104. }
    105. }
    106. class person {
    107. int x;
    108. int y;
    109. String path;
    110. person(int x_, int y_, String path_) {
    111. x = x_;
    112. y = y_;
    113. path = path_;
    114. }
    115. }
    116. class node {
    117. int px, py, bx, by;
    118. String path;
    119. node(int px_, int py_, int bx_, int by_, String path_) {
    120. px = px_;
    121. py = py_;
    122. bx = bx_;
    123. by = by_;
    124. path = path_;
    125. }
    126. }

    七 测试

  • 相关阅读:
    【数据结构】分块查找
    react基本使用
    基于DBC Signal Group生成Autosar SR接口(2)
    fastadmin在前端调用 /api/common/upload 返回未上传文件或超出服务器上传限制
    30分钟学完mysql的基本操作和语法(图文解说)
    第6章 docker资源限制
    协作机器人应用场景
    TLS重连,TLS 和 TCP 能否同时握手
    每天3分钟,重学ES6-ES12(十五)异步代码处理方案
    长安链EVM合约地址与数据库存储账户的关系及计算
  • 原文地址:https://blog.csdn.net/chengqiuming/article/details/126448034