幅優先探索 (BFS) で知らせが全員に届くまでの分を数える

座席の表で、知らせを持つ人から上下左右の人へ 1 分ずつ知らせが広がるとき、全員に届くまでの分を数えます。始めに知らせを持つ人を全員、同時に列へ入れて段ごとに広げる練習です。

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

問題

教室の座席を 2 次元の並び grid で受け取ります。各マスは次のどれかの数です。

  • 0 は空いている席です
  • 1 は、まだ知らせを知らない人が座っている席です
  • 2 は、知らせを知っている人が座っている席です

1 分たつごとに、知らせを知っている人は、上下左右で隣り合う席の、知らない人へ知らせを伝えます。伝わった人は、次の 1 分から伝える側になります。空いている席を飛び越えては伝わりません。知らない人がいなくなるまでの分を返す関数を書いてください。どれだけたっても知らせが届かない人がいるなら -1 を返します。

  • 始めから知らない人がいなければ 0 を返します
  • 行の数と列の数は、どちらも 1 以上 10 以下です。どの行も同じ長さです
  • 関数の中で grid を書き換えてかまいません

入力と出力の例

例 1

左下の人から、1 分で上と右、2 分でその先、と広がります。右上の人に届くのは 4 分後です。

grid = [[1, 1, 1], [1, 0, 1], [2, 1, 1]]
4

例 2

右上の人は、隣が空いている席だけなので、知らせが届きません。

grid = [[2, 1, 0, 1], [0, 1, 0, 0]]
-1

例 3

知っている人が 2 人いて、両側から同時に広がります。まん中の人に 1 分、その隣の 2 人に 1 分で、2 分後に全員に届きます。

grid = [[2, 1, 1, 1, 2]]
2

面接での聞かれ方

面接では、短く次のように渡されることが多いです。

  • 「グリッドに新鮮なオレンジと腐ったオレンジがあり、毎分、腐ったオレンジの隣が腐ります。全部腐るまでの分を返してください。無理なら -1 です」
  • 1 つずつ始めの点から探す書き方を出すと、「始めの点がいくつもあるとき、まとめて 1 回で探せませんか?」と聞かれます
  • 「始めから新鮮な物が無いときは?」と、端の答えを聞かれます

始めに知らない人がいないときと、届かない人がいるときの答えを最初に確かめておくと、最後の返し方で迷いません。

ヒント

まだ開いていません

付箋は 4 枚。下の段ほど答えに近づきます

  1. ヒント 2

  2. ヒント 3

  3. ヒント 4答えに近い

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

グラフ探索は、つながりを近い順か奥からたどります。迷路、最短の手数、講座を受ける順のような問題が同じ形です。

main.py
def spread_minutes(grid: list[list[int]]) -> int:
    """
    Goal: 何を返すか

    idea1: まず思いつく案
    -> runtime: O(?)  space: O(?)

    idea2: もっと速い案
    -> runtime: O(?)  space: O(?)

    edge case: 空、1 つだけ、など
    """
    # ここに書きます
    pass


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

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