3812 机器人走迷宫(枚举 + 全排列)

1. 问题描述:

有一个 n × m 个单元格构成的迷宫,其中空单元格用 . 表示,障碍物用 # 表示。迷宫中有一个机器人,它的起点位置用 S 表示,目标位置用 E 表示,这两个地点均没有障碍。机器人只能沿上下左右四个方向移动。给定一串由数字 0∼3 构成的字符串,表示机器人的行动指令列表。机器人将按照列表中的指令,依次进行移动。在执行指令的过程中:
如果机器人走出迷宫边界或者碰到障碍物,则机器人会损坏。
如果机器人到达目标位置,则停止行动,不再接受后续指令。
现在,哪个数字(0∼3)对应哪种行动(上下左右)还未分配。
请问,共有多少种分配方案,能够使得机器人顺利到达目标位置。

输入格式

第一行包含整数 T,表示共有 T 组测试数据。每组数据第一行包含两个整数 n 和 m。接下来 n 行,每行包含 m 个字符,表示迷宫。所有字符均为 ., #,,S, E 之一,其中 S 和 E 出现且仅出现一次。最后一行包含一个字符串 s 表示指令列表,每个字符均为 0∼3 之一。

输出格式

每组数据输出一行结果,表示能够使得机器人顺利到达目标位置的行动指令分配方案数量。

数据范围

前三个测试点满足 2 ≤ n, m ≤ 10。
所有测试点满足 1 ≤ T ≤ 10,2 ≤ n,m ≤ 50,1 ≤ |s| ≤ 100。
同一测试点内,所有 n × m 的和不超过 2500。

输入样例:

2
5 6
.....#
S....#
.#....
.#....
...E..
333300012
6 6
......
......
..SE..
......
......
......
01232123212302123021

输出样例:

1
14
来源:https://www.acwing.com/problem/content/description/3815/

2. 思路分析:

因为0~3对应的上下左右四个方向是不确定的所以我们可以枚举所有的可能,总的方案数目为4的全排列也即有24种可能,所以我们可以枚举24种不同的方向,可以使用递归交换元素的方法生成[0,1,2,3]的全排列,然后枚举所有的排列,判断s按照当前排列对应的方向执行是否可以到达终点,如果可以到达终点那么计数加1即可。

3. 代码如下:

from typing import List


class Solution:
    pos = [[0, 1], [0, -1], [1, 0], [-1, 0]]

    # 交换元素生成全排列
    def get(self, k: int, a: List[int], res: List[List[int]]):
        if k == 4:
            # a[:]为拷贝a的副本, 将其添加到res中
            res.append(a[:])
            return
        for i in range(k, 4):
            a[i], a[k] = a[k], a[i]
            self.get(k + 1, a, res)
            # 恢复现场
            a[i], a[k] = a[k], a[i]

    def check(self, n: int, m: int, x: List[int], s: str, start: List[int], end: List[int], g: List[List[str]]):
        a, b = start[0], start[1]
        for i in range(len(s)):
            k = int(s[i])
            a, b = a + self.pos[x[k]][0], b + self.pos[x[k]][1]
            if a < 0 or a >= n or b < 0 or b >= m or g[a][b] == "#": return False
            # 说明到达了终点
            if a == end[0] and b == end[1]: return True
        return a == end[0] and b == end[1]

    def process(self):
        a = [0, 1, 2, 3]
        res = list()
        # 生成a的所有全排列
        self.get(0, a, res)
        T = int(input())
        while T:
            n, m = map(int, input().split())
            g = list()
            # start, end记录起点和终点的坐标
            start, end = [-1, -1], [-1, -1]
            for i in range(n):
                s = input()
                g.append(list(s))
                for j in range(m):
                    if s[j] == "S":
                        start[0], start[1] = i, j
                    if s[j] == "E":
                        end[0], end[1] = i, j
            s = input()
            count = 0
            for x in res:
                # 判断当前设置的方向是否可以到达终点
                if self.check(n, m, x, s, start, end, g):
                    count += 1
            print(count)
            T -= 1


if __name__ == '__main__':
    Solution().process()
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值