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