推箱子问题

一 问题描述

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

二 输入和输出

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

六 代码

package com.platform.modules.alg.alglib.poj1475;

import java.util.LinkedList;
import java.util.Queue;

public class Poj1475 {
    public String output = "";

    private int N;
    private int M;
    char mp[][] = new char[25][25];
    // 人和箱子的初始位置
    private int sx;
    private int sy;
    private int bx;
    private int by;

    private final int dir[][] = {{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
    private final char dpathB[] = {'N', 'S', 'E', 'W'};
    private final char dpathP[] = {'n', 's', 'e', 'w'};
    private String ans;

    public String cal(String input) {
        String[] line = input.split("\n");
        String[] words = line[0].split(" ");
        N = Integer.parseInt(words[0]);
        M = Integer.parseInt(words[1]);
        for (int i = 0; i < N; i++) {
            String mapLine = line[i + 1];
            for (int j = 0; j < mapLine.length(); j++) {
                mp[i][j] = mapLine.charAt(j);
                if (mp[i][j] == 'S') {
                    sx = i;
                    sy = j;
                }

                if (mp[i][j] == 'B') {
                    bx = i;
                    by = j;
                }
            }
        }
        if (bfs())
            output += ans;
        else
            output += "Impossible";
        return output;
    }

    boolean check(int x, int y) {
        if (x < 0 || x >= N || y < 0 || y >= M) return false;
        if (mp[x][y] == '#') return false;
        return true;
    }

    boolean bfs() {
        int vis[][] = new int[25][25];
        vis[bx][by] = 1;
        Queue<node> q = new LinkedList<>(); // 创建一个普通队列(先进先出)
        q.add(new node(sx, sy, bx, by, ""));
        while (!q.isEmpty()) {
            node now = q.peek();
            q.poll();
            for (int i = 0; i < 4; i++) {
                // 箱子的新位置
                int nbx = now.bx + dir[i][0];
                int nby = now.by + dir[i][1];
                // 箱子的前一个位置,人必须能到达这个位置
                int tx = now.bx - dir[i][0];
                int ty = now.by - dir[i][1];
                String path = "";
                StringBuilder pathBuilder = new StringBuilder(path);
                if (check(nbx, nby) && check(tx, ty) && vis[nbx][nby] == 0) {
                    if (bfs2(now.px, now.py, now.bx, now.by, tx, ty, pathBuilder)) {
                        if (mp[nbx][nby] == 'T') {
                            ans = now.path + path + dpathB[i];
                            return true;
                        }
                        vis[nbx][nby] = 1;
                        q.add(new node(now.bx, now.by, nbx, nby, now.path + pathBuilder.toString() + dpathB[i]));
                    }
                }
            }
        }
        return false;
    }

    boolean bfs2(int ppx, int ppy, int bbx, int bby, int tx, int ty, StringBuilder pathBuilder) {
        // 局部标识数组,不要定义全局
        int vis[][] = new int[25][25];
        vis[ppx][ppy] = 1; // 人的位置
        vis[bbx][bby] = 1; // 箱子的位置
        Queue<person> Q = new LinkedList<>(); // 创建一个普通队列(先进先出)
        Q.add(new person(ppx, ppy, ""));
        while (!Q.isEmpty()) {
            person now = Q.peek();
            Q.poll();
            if (now.x == tx && now.y == ty) { // 目标位置,即箱子的前一个位置
                pathBuilder.append(now.path);
                return true;
            }
            for (int i = 0; i < 4; i++) {
                // 人的新位置
                int npx = now.x + dir[i][0];
                int npy = now.y + dir[i][1];
                if (check(npx, npy) && vis[npx][npy] == 0) {
                    vis[npx][npy] = 1;
                    Q.add(new person(npx, npy, now.path + dpathP[i]));
                }
            }
        }
        return false;
    }
}

class person {
    int x;
    int y;
    String path;

    person(int x_, int y_, String path_) {
        x = x_;
        y = y_;
        path = path_;
    }
}

class node {
    int px, py, bx, by;
    String path;


    node(int px_, int py_, int bx_, int by_, String path_) {
        px = px_;
        py = py_;
        bx = bx_;
        by = by_;
        path = path_;
    }
}

七 测试

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Funcode推箱子是一款休闲益智类游戏,玩家需要通过推动箱子来将它们全部放到目标位置上,以完成关卡的任务。 玩家在游戏中扮演的是推箱子工人的角色,游戏地图上会有墙壁、目标位置、箱子和工人四种元素。玩家通过控制工人的移动,将箱子推动到目标位置上即可过关。但是要注意,箱子只能被推动而不能被拉动,而且一个工人只能推动一个箱子。 游戏的难度会随着关卡的逐渐升级而增加,地图上的障碍物会变得越来越多,需要玩家进行合理规划和操作。有些关卡需要玩家进行多次推箱子的移动和交换位置,才能达到目标。而有些关卡则需要运用一些特殊的技巧或利用地图上的道具来解决难题。 游戏中还有计时的限制,要求玩家在规定的时间内完成任务,这增加了游戏的挑战性。如果无法在限定时间内完成任务,则需要重新尝试。 Funcode推箱子的设计简单而有趣,能够锻炼玩家的逻辑思维和空间想象力。更重要的是,推箱子可以帮助玩家放松身心,缓解压力,成为休闲娱乐的好选择。无论是在手机上还是在电脑上,Funcode推箱子都是一款非常受欢迎的游戏。 ### 回答2: 《FunCode 推箱子》是一款经典的益智游戏,玩家需要在规定的地图上将箱子推到指定的目标位置,以完成关卡任务。 玩家通过控制游戏角色在地图上移动,并推动箱子,沿着空位移动箱子,直到将其推至目标位置。同时,玩家需要避免陷入困境,比如将箱子堵住或者将自己困在某个位置无法移动。 游戏的难度逐渐递增,关卡设计有趣且挑战性。玩家需要仔细观察地图布局,合理规划移动路径,利用思维和逻辑进行推理,才能找到最佳解决方案。 《FunCode 推箱子》不仅能够锻炼玩家的空间想象力、逻辑思维和问题解决能力,还能培养耐心和执着精神。很多关卡都需要反复尝试和调整策略,只有坚持不懈,才能取得成功。 此外,《FunCode 推箱子》还提供了多个关卡和地图选择,玩家可以根据自己的兴趣和能力选择合适的挑战。同时,游戏内置了排行榜和成就系统,玩家可以和朋友们比较成绩,增加游戏的互动性和竞争性。 总体而言,《FunCode 推箱子》是一款兼具趣味性和教育性的益智游戏。不仅能够帮助玩家锻炼大脑,提升思维能力,还能带给玩家娱乐和挑战的享受。无论是孩子还是成年人,都能从中受益,值得一试。 ### 回答3: 《FunCode 推箱子》是一款经典的益智游戏。在游戏中,玩家需要将箱子推到预定的目标位置,通过这样的操作解决谜题,取得胜利。 这款游戏的规则相对简单。玩家可以通过上下左右四个方向的滑动来操纵主角移动。玩家需要利用地图上的障碍物、箱子和目标位置之间的关系,合理规划移动顺序,达到把所有箱子推进目标位置的目标。 游戏设置了多个关卡,难度逐渐加大。初始关卡比较简单,而后随着关卡的递增,地图上的障碍物和目标位置的数量和布局会变得更加复杂,需要思考更多步骤。玩家需要巧妙地运用游戏规则,创造性地解决难题才能通过每一关。 推箱子这款游戏有助于锻炼玩家的逻辑思维能力和空间想象力。在解决谜题的过程中,玩家需要分析地图布局,预估每一步的影响,避免陷入死胡同。这样的思考训练能够提高玩家的问题解决和决策能力,培养耐心和专注力。 《FunCode 推箱子》以其简单但紧张刺激的游戏体验受到许多玩家的喜爱。它提供了大量关卡可以挑战,玩家可以根据自己的能力选择不同的难度。这款游戏不仅可以带给玩家乐趣,还能够激发玩家的智力潜能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值