188 武士风度的牛(bfs)

1. 问题描述:

农民 John 有很多牛,他想交易其中一头被 Don 称为 The Knight 的牛。这头牛有一个独一无二的超能力,在农场里像 Knight 一样地跳(就是我们熟悉的象棋中马的走法)。虽然这头神奇的牛不能跳到树上和石头上,但是它可以在牧场上随意跳,我们把牧场用一个 x,y 的坐标图来表示。这头神奇的牛像其它牛一样喜欢吃草,给你一张地图,上面标注了 The Knight 的开始位置,树、灌木、石头以及其它障碍的位置,除此之外还有一捆草。现在你的任务是,确定 The Knight 要想吃到草,至少需要跳多少次。The Knight 的位置用 K 来标记,障碍的位置用 * 来标记,草的位置用 H 来标记。这里有一个地图的例子:
             11 | . . . . . . . . . .
             10 | . . . . * . . . . . 
              9 | . . . . . . . . . . 
              8 | . . . * . * . . . . 
              7 | . . . . . . . * . . 
              6 | . . * . . * . . . H 
              5 | * . . . . . . . . . 
              4 | . . . * . . . * . . 
              3 | . K . . . . . . . . 
              2 | . . . * . . . . . * 
              1 | . . * . . . . * . . 
              0 ----------------------
                                    1 
                0 1 2 3 4 5 6 7 8 9 0 
The Knight 可以按照下图中的 A,B,C,D… 这条路径用 5 次跳到草的地方(有可能其它路线的长度也是 5):
             11 | . . . . . . . . . .
             10 | . . . . * . . . . .
              9 | . . . . . . . . . .
              8 | . . . * . * . . . .
              7 | . . . . . . . * . .
              6 | . . * . . * . . . F<
              5 | * . B . . . . . . .
              4 | . . . * C . . * E .
              3 | .>A . . . . D . . .
              2 | . . . * . . . . . *
              1 | . . * . . . . * . .
              0 ----------------------
                                    1
                0 1 2 3 4 5 6 7 8 9 0
注意: 数据保证一定有解。

输入格式

第 1 行: 两个数,表示农场的列数 C 和行数 R。第 2..R+1 行: 每行一个由 C 个字符组成的字符串,共同描绘出牧场地图。

输出格式

一个整数,表示跳跃的最小次数。

数据范围

1 ≤ R,C ≤ 150

输入样例:

10 11
..........
....*.....
..........
...*.*....
.......*..
..*..*...H
*.........
...*...*..
.K........
...*.....*
..*....*..

输出样例:
5
来源:https://www.acwing.com/problem/content/description/190/

2. 思路分析:

分析题目可以知道这道题目与走迷宫的题目基本上是一样的,都是求解从起点到终点的最短距离,这道题目可以连通的方向不是四连通或者是八连通,是"日"字型的走法,所以我们只需要修改一下可以走的八个方向的坐标即可,其余的都是一样的。

188 武士风度的牛(bfs)_第1张图片

3. 代码如下:

import collections
from typing import List


class Solution:
    def bfs(self, x: int, y: int, n: int, m: int, g: List[str]):
        # (x, y)是起点, deque为双端队列
        q = collections.deque([(x, y)])
        # 周围可以走的八个方向
        pos = [[-1, -2], [-2, -1], [-1, 2], [-2, 1], [2, 1], [1, 2], [2, -1], [1, -2]]
        # dis除了可以记录最短距离之外还相当于是判重数组
        dis = [[-1] * (m + 10) for i in range(n + 10)]
        dis[x][y] = 0
        while q:
            # 弹出队首元素
            x0, y0 = q.popleft()
            for i in range(8):
                a, b = x0 + pos[i][0], y0 + pos[i][1]
                # 超出了边界
                if a < 0 or a >= n or b < 0 or b >= m: continue
                # 障碍
                if g[a][b] == "*": continue   
                # 之前有位置到达了当前的位置第一次到的是最短距离
                if dis[a][b] != -1: continue
                # 因为题目一定有解所以返回对应的最短距离即可
                if g[a][b] == "H": return dis[x0][y0] + 1
                # 未到达终点所以需要将其加入到队列, 并且距离需要加1
                q.append((a, b))
                dis[a][b] = dis[x0][y0] + 1
        return -1

    def process(self):
        m, n = map(int, input().split())
        g = list()
        for i in range(n):
            g.append(input())
        x, y = 0, 0
        for i in range(n):
            for j in range(m):
                if g[i][j] == "K":
                    x, y = i, j
                    break
        return self.bfs(x, y, n, m, g)


if __name__ == '__main__':
    print(Solution().process())

你可能感兴趣的:(acwing-提高,算法)