亲子游戏 (200)
- 在一个二维矩阵(n*n)的格子地图上,宝宝和妈妈抽签决定各自的位置,每个格子有不同数量的糖果,部分格子有障碍物;
- 游戏规则,妈妈必须在最短的时间(每次走一步)到达宝宝的位置,路上的糖果都可以拿走,不能走障碍物的格子,只能上下左右的走;
- 妈妈在最短到达宝宝位置的时间内最多拿到多少糖果。
输入描述:
第一行输入n;
后续n行,每行有n个值,-3表示妈妈,-2表示宝宝,-1表示障碍物,>=0表示糖果数,0没有糖果,但可以通过;
输出描述:
妈妈在最短到达宝宝位置的时间内最多拿到多少糖果,地图最大50*50;
若无法到达宝宝位置,则输出-1
示例1
输入:
4
3 2 1 -3
1 -1 1 1
1 1 -1 2
-2 1 2 3
输出:
9
示例2
输入:
4
3 2 1 -3
-1 -1 1 1
1 1 -1 2
-2 1 -1 3
输出:
-1
思路:
- BFS/DFS
- 先找最短路径(最少步子),在最短路径的情况下,再找最多糖果数;
- 两次BFS
class MBGame:
def solution(self, n, arr):
self.visited = [[0 for j in range(n)] for i in range(n)]
# 找妈妈的位置
self.mother_pos = self.find_pos(n, arr, -3)
# 找baby的位置
self.baby_pos = self.find_pos(n, arr, -2)
# 寻找最短路径(广度优先)
steps = self.BFS(n)
print("最短路径:", steps)
# 计算在最短路径下的最大糖果数(走 steps 步)
candy_arr = [[-1 for i in range(n)] for j in range(n)] # 不能用visited控制访问过程
candy_arr[self.mother_pos[0]][self.mother_pos[1]] = 0 # 起始位置糖果数为0
# 再次广度优先
queue = [self.mother_pos]
while True:
if steps <= 0:
break
# 出队
size = len(queue)
for i in range(size):
cur_pos = queue.pop(0)
# 从当前格子走四个方向
x, y = cur_pos
directions = [(x, y + 1), (x, y - 1), (x - 1, y), (x + 1, y)]
for new_x, new_y in directions:
# 新位置有效、不为-1、未走过,则可以走
if 0 <= new_x < n and 0 <= new_y < n and arr[new_x][new_y] != -1:
if candy_arr[new_x][new_y] == -1:
# 入队
queue.append((new_x, new_y))
# 更新新位置的糖果数
if arr[new_x][new_y] != -2: # 没到终点
candy_arr[new_x][new_y] = max(candy_arr[new_x][new_y],
candy_arr[x][y] + arr[new_x][new_y])
else: # 可以用2x2的 矩阵演示说明
candy_arr[new_x][new_y] = max(candy_arr[new_x][new_y],
candy_arr[x][y])
steps -= 1
for i in range(n):
print("candy_arr:", candy_arr[i]) # 终点位置即为最大糖果数
print(candy_arr[self.baby_pos[0]][self.baby_pos[1]])
def BFS(self, n):
# 起始点入队
queue = []
queue.append(self.mother_pos)
# flag 标识是否能走到终点
flag = False
# 走的步子数
steps = 0
# 循环出队
while True:
size = len(queue)
if size <= 0: # 判断队列是否为空
break
for i in range(size): # 当前层级的所有的位置,作为起始点(同时向外层走一步)
start_pos = queue.pop(0)
# 判断当前位置是否为终止位置
x, y = start_pos
if arr[x][y] == -2:
flag = True # 走到终点,直接结束
break
else:
# 从当前位置,开始走四个方向
directions = [(x, y+1), (x, y-1), (x-1, y), (x+1, y)]
for new_x, new_y in directions:
# 新位置有效、不为-1、未走过,则可以走
if 0 <= new_x < n and 0 <= new_y < n and arr[new_x][new_y] != -1 and \
self.visited[new_x][new_y] == 0:
self.visited[new_x][new_y] = 1 # 表示已走过
# 新位置入队
queue.append((new_x, new_y))
if flag: # 走到终点,则提前终止外层循环
break
# 走一步
steps += 1
if not flag: # 无法到达终点
return -1
# 到达终点
return steps # 第一个搜索到达的路径,一定是最短路径
def find_pos(self, n, arr, val):
for i in range(n):
for j in range(n):
if arr[i][j] == val:
m_pos = (i, j)
return m_pos
if __name__ == '__main__':
mb_game = MBGame()
# 3 2 1 -3
# 1 -1 1 1
# 1 1 -1 2
# -2 1 2 3
while True:
try:
n = int(input().strip())
arr = []
for i in range(n):
arr.append(list(map(int, input().strip().split())))
mb_game.solution(n, arr)
except KeyboardInterrupt:
break