华为 OD 机试:亲子游戏
问题描述
母親と赤ちゃんが参加する親子ゲームがあります。N×N の2次元グリッドマップ上で、母親と赤ちゃん的位置を决めます。各セルには異なる数のキャンディーが入っており、一部のセルには障害物があります。
ゲームルールは、母親が最短時間で赤ちゃんの位置に到達する必要があります(各单位時間には1マスだけ移动できます)。道沿いのすべてのキャンディーを回収できます。障害物のセルは通行不可で、上下左右のみ移動可能です。
最短時間で赤ちゃんに到達する間に、最大で何個のキャンディーを回収できるかを出力してください(最短到達時間を优先し、その条件下で 최대한多くのキャンディーを得ることを优先します)。
输入格式
最初の一行目に N が与えられ、N は2次元矩阵のサイズを表します。 その後に N 行、各行に N の値があります。
值の説明:
-3:母親の位置-2:赤ちゃんの位置-1:障害物>=0:キャンディーの数(0 はキャンディーがありませんが、通行可能です)
输出格式
母親が最短到达时间内に获取できる最多的糖果数を 출력します。行末に余分な空白はありません。
备注
マップのサイズは最大 50×50 です。
示例一
输入
4
3 2 1 -3
1 -1 1 1
1 1 -1 2
-2 1 2 3
输出
9
说明
このマップには最短経路が2通りあります。緑色の線と黄色の線は両方とも最短距離6ステップですが、黄色の経路の方が多くのキャンディーを获取でき、9個になります。
示例二
输入
4
3 2 1 -3
-1 -1 1 1
1 1 -1 2
-2 1 -1 3
输出
-1
说明
このマップでは母親は赤ちゃんの位置に到達できません。
解题思路
最短路径の计算には BFS(幅優先探索)が适しています。难しいのは、最短路径の条件の下で最大のキャンディー数を计算することです。
BFS は层ごとに探索を行うため、まず各路径の長さを記録し、同じ长度の路径之间でキャンディー数の比较を行います。
题解
import collections
# グリッドのサイズ
grid_size = 4
# ゲームマップの定義
game_map = """
3 2 1 -3
1 -1 14 5
1 1 1 2
-2 1 2 3
""".strip()
# 文字列から2次元リストに変換
grid = [list(map(int, row.split())) for row in game_map.split('\n')]
# BFS 用キュー (行, 列, キャンディー数)
search_queue = collections.deque()
# 訪問済みフラグ
visited = [[False] * grid_size for _ in range(grid_size)]
# 母親の開始位置を探してキューに設定
start_row, start_col = 0, 0
for i in range(grid_size):
for j in range(grid_size):
if grid[i][j] == -3:
start_row, start_col = i, j
search_queue.append((start_row, start_col, 0))
visited[start_row][start_col] = True
# 現在のタイムステップ
current_time = 0
# 結果リスト: [タイムステップ, キャンディー数]
valid_results = []
while search_queue:
# 現在の層のキューサイズ
level_size = len(search_queue)
# 次の層のデータを一時保存
next_level_items = []
for _ in range(level_size):
row, col, candy_count = search_queue.popleft()
# 上下左右の移動方向
for dr, dc in [(0, 1), (0, -1), (1, 0), (-1, 0)]:
new_row, new_col = row + dr, col + dc
# グリッド範囲内かつ障害物でないかつ未訪問
if (0 <= new_row < grid_size and
0 <= new_col < grid_size and
grid[new_row][new_col] != -1 and
not visited[new_row][new_col]):
# 赤ちゃんの位置に到達した場合
if grid[new_row][new_col] == -2:
valid_results.append([current_time, candy_count])
break
# 訪問済み标记
visited[new_row][new_col] = True
# 現在のキャンディー数を加えて次の层に追加
cell_value = grid[new_row][new_col]
next_level_items.append((new_row, new_col, candy_count + cell_value))
# 現在の層の処理结束后、キャンディー数が多い顺に排序してキューに追加
for item in sorted(next_level_items, key=lambda x: -x[2]):
search_queue.append(item)
# タイムステップを進める
current_time += 1
# 결과 출력
if not valid_results:
print(-1)
else:
# 最小のタイムステップを見つける
min_time = min(result[0] for result in valid_results)
# そのタイムステップの中で最大のキャンディー数を見つける
max_candies = max(result[1] for result in valid_results if result[0] == min_time)
print(max_candies)
关键点说明
-
BFS の层遍历:BFS を使用することで、从最短路径부터逐层探索 保证します。
-
同一时间内の最优选择:同しタイムステップ内で多个路径がある場合、キャンディー数が多いてなるように排序します。これにより、最短时间内で尽可能多くのキャンディーを获取できます。
-
访问控制:各セルは1回だけ访问し、二重探索を回避します。
-
结果选择:最後に、最短到达时间(最小タイムステップ)の中で最大のキャンディー数を出力します。到达できない场 합は -1 を出力します。