幅優先探索 (BFS) でグリッドの最短の道を数える

通れる​マスと​ふさがった​マスの​地図で、​左上から​右下まで​ 8 方向に​進むときの​最短の​道の​マスの​数を​返す。​近い​マスから​順に​広げる​幅優先で、​最初に​着いた​時の​歩数が​答えに​なります。

海外で定番の問題リスト 4 本には入っていません

問題

n 行 n 列の地図 grid を受け取ります。各マスは数の 0 (通れる) か 1 (ふさがっている) です。左上のマスから右下のマスまで、通れるマスだけを通って進みます。1 歩で、上下左右と斜めの 8 方向のどれかの隣のマスへ進めます。いちばん短い道で通るマスの数 (左上と右下も数えます) を返す関数を書いてください。

  • 道が無いときは -1 を返します。左上か右下がふさがっているときも -1 です
  • n が 1 のとき、左上と右下は同じマスです。そこが通れれば答えは 1 です
  • n は 1 以上 100 以下です

入力と出力の例

例 1

下へ 1 歩、右下へ斜めに 1 歩、右へ 1 歩で、4 つのマスを通ります。

入力

grid = [[0, 1, 1],
  [0, 1, 1],
  [1, 0, 0]]

出力

4

例 2

左上がふさがっているので、歩き始められません。

入力

grid = [[1, 0],
  [0, 0]]

出力

-1

例 3

下へ、右下へ、右上へ、右下へ、下へと、斜めを使って壁をよけながら進みます。左上と右下を含めて 6 つのマスです。

入力

grid = [[0, 1, 0, 0],
  [0, 1, 0, 1],
  [0, 0, 1, 0],
  [1, 1, 1, 0]]

出力

6

面接での聞かれ方

面接では、迷路やロボットの移動の場面で渡されることが多いです。

  • 「0 と 1 の地図で、左上から右下までの最短の長さを返してください」
  • 書き終えたあとに「なぜ深さ優先ではだめなのですか?」「最初に着いた時が最短だと言える理由は?」と続けて聞かれます
  • 「マスごとに通る手間が違うなら、どう変えますか?」と、重みのある最短の道へ広げて聞かれることもあります

長さを「歩数」で数えるのか「通るマスの数」で数えるのかで、答えが 1 つずれます。書く前に、例で確かめておきます。

アルゴリズムのチートシートの「グラフ探索と幅優先探索」に、​この​型の​要点を​表と​コードで​まとめています。

main.py
def shortest_path(grid):
    # ここに書きます
    pass


# 「実行」を押すと、この行の結果が出ます
print(shortest_path([[0, 1, 1], [0, 1, 1], [1, 0, 0]]))

できているか「例で確かめる」を押すと、問題の例を全部この関数に渡して、通ったかをここに出します