ひとりで勝手にはじめた蟻本読書会 幅優先探索と深さ優先探索 意外と奥が深い全探索 蟻本読書会の続きです。

迷路の最短路を幅優先探索で探す

迷路の最短路を探すときも幅優先探索を使います。深さ優先探索でもできますが、探索空間 (グラフのサイズ) 自体がとても大きいが、解がスタートから近いところにある場合は幅優先探索が適していると考えられています。

幅優先探索

このページをみると図付きで、幅優先探索を用いた迷路の最短路を探す方法が説明されていますね。

C – 幅優先探索

盤面のサイズと、迷路のスタート地点とゴール地点の座標が与えられる。
次に、それぞれのマスが通行可能な空きマス(.)か通行不可能な壁マス(#)かという情報を持った盤面が与えられる。盤面は壁マスで囲まれている。スタート地点とゴール地点は必ず空きマスであり、スタート地点からゴール地点へは、空きマスを辿って必ずたどり着ける。

上記の迷路を解くのに必要な最小移動手数を求めたい。
スタート地点からゴール地点に移動する最小手数を 1 行に出力せよ。

入力
R C
sy sx
gy gx
c_1,1 c_1,2 c_1,3 … c_1,C
c_2,1 c_2,2 c_2,3 … c_2,C

c_R,1 c_R,2 c_R,3 … c_R,C
(ただし 1 ≦ R, C ≦ 50, 1 ≦ sy, gy ≦ R かつ 1 ≦ sx, gx ≦ C
c_i,1 c_i,2 c_i,3 … c_i,C の各文字の間には半角スペースなし
各文字は . もしくは # のいずれか)

入力例
7 8
2 2
4 5
########
#……#
#.######
#..#…#
#..##..#
##…..#
########

出力例
11

最小移動手数を2次元配列 cost に記憶していきます。副産物としてそれ以外のマスに対する最短手数もわかります。

D – Grid Repainting

D – Grid Repainting

縦 H マス, 横 W マスに広がるマス目があり、各マスは白または黒で塗られている。上から i 番目で左から j 番目のマスを (i, j) で表す。このマス目を使って次のようなゲームをしたい。

ゲームの開始時点ではマス (1, 1) にゲームキャラクター「けぬす君」がいる. プレイヤーはけぬす君を上下左右の 4 方向のいずれかに 1 マスだけ動かすことを繰り返す。けぬす君が白いマスだけを通って (H, W) にたどり着けばゲームクリアとなる。ゲームを開始する前にすぬけ君はいくつかの白いマス目の色を黒に変えることができる。ただしマス (1, 1) と (H, W) の色を変えることはできない。

ゲームをクリアしたときゲームの開始前にマスの色を変えた回数がスコアとなる。そのとき可能性のある最大のスコアを求めなさい。ただしどのようにマス目の色を変えてもけぬす君が (H, W) にたどり着くことができない場合は -1 と出力しなさい。

入力
H W
‘#’,’.’ からなる W 文字の文字列が H 行
(ただし 2 ≦ H, W ≦ 50。
‘#’は最初から黒で塗られている部分,’.’は白で塗られている部分である)

これはこのように考えてよいのではないでしょうか?

クリアしたときゲームの開始前にマスの色を黒に変えた回数がスコアとなり、スコアを最大にするのであれば必要最小限の部分だけ残してすべて黒く塗ってしまえばよい。白いまま残すべきマスの個数は最短手順に1を足した数である。

ということで(マスの総数)-(最初から黒だったマスの数)-(塗らずに残すべきマスの数)が答えということになります。ただしゴールにたどり着けない場合があるのでそれも考えなければなりません。これは幅優先探索の処理が終わったときにゴールまでの最短手数を記録する部分が初期値から変わっているかでわかります。初期値のままだと “-1” を出力することになります。

最短手数を複数回求める

E – チーズ (Cheese)

今年も JOI 町のチーズ工場がチーズの生産を始め,ねずみが巣から顔を出した。JOI 町は東西南北に区画整理されていて各区画は巣、チーズ工場、障害物、空き地のいずれかである。ねずみは巣から出発して全てのチーズ工場を訪れチーズを 1 個ずつ食べる。

この町には N 個のチーズ工場があり、どの工場も 1 種類のチーズだけを生産している.チーズの硬さは工場によって異なっており、硬さ 1 から N までのチーズを生産するチーズ工場がちょうど 1 つずつある。

ねずみの最初の体力は 1 であり、チーズを 1 個食べるごとに体力が 1 増える。ただしねずみは自分の体力よりも硬いチーズを食べることはできない。

ねずみは東西南北に隣り合う区画に 1 分で移動することができるが障害物の区画には入ることができない。チーズ工場をチーズを食べずに通り過ぎることもできる。すべてのチーズを食べ終えるまでにかかる最短時間を求めるプログラムを書け。ただしねずみがチーズを食べるのにかかる時間は無視できる。

入力
H W N
‘S’,’1’,’2’,…,’9’,’X’,’.’ からなる W 文字の文字列が H 行
(ただし 1 ≦ H, W ≦1000, 1 ≦ N ≦ 9)

巣 S
障害物 X
空き地 .
硬さ i のチーズを生産する工場は数字
ねずみはすべてのチーズを食べられることが保証されている

これは硬さ 1 から N まで順番に回ればよいのではないでしょうか? 巣から硬さ1のチーズ工場へ、さらにそこから硬さ1のチーズ工場へという具合に。ねずみはすべてのチーズを食べられることが保証されているため、障害物で食べることはできないということはないようです。

上記のコードはスタート地点からゴールに到達すれば終わりでしたが、今回はゴール地点が新しいスタート地点となって新しいゴールを目指すという処理を繰り返します。最短手数を記録する配列もそのつど作り直します。

マップの縦横が最大で1000であること、最短経路を探す繰り返しの回数が最大で9回なので、以下のコードで充分間に合います。

迷路内の移動にかかるコスト

これまで迷路内を移動するときに最短手数を記録する手法を使いましたが、移動するときには移動先によってコストが必要となり、コストの最小値を問うような問題も出題されます。器物損壊!高橋君はそんな問題です。

C – 器物損壊!高橋君

彼の住む街は長方形の形をしており、格子状の区画に区切られています。区画は道または塀のどちらかであり、高橋君は道を東西南北に移動できますが斜めには移動できません。また、塀の区画は通ることができません。高橋君の家から魚屋までの道のりは非常に複雑なため、単純に歩くだけでは辿り着くことは困難です。

しかし、高橋君は腕力には自信があるので道に上下左右で面している塀を 2 回までなら壊して道にすることができます。高橋君が魚屋に辿り着くことができるかどうか答えてください。

入力
H W
‘s’,’g’, ‘#’,’.’ からなる W 文字の文字列が H 行

(ただし 1 ≦ H, W ≦ 500)
‘s’ : その区画が家であることを表す。
‘g’ : その区画が魚屋であることを表す。
‘.’ : その区画が道であることを表す。
‘#’ : その区画が塀であることを表す。

移動するためのコストを考えます。塀以外の場所に移動するのであればコストは0、塀がある場所に移動するのであればコスト1が必要であるということにして、魚屋にたどりつくまでの最小コストを考えます。魚屋にたどり着くためのコストが破壊しなければならない壁の数です。これが2以下であれば”YES”を出力し、それよりも大きければ”NO”を出力します。

開始点が複数ある幅優先探索

A – Darker and Darker

縦 H 行、横 W 列の白黒に塗られたマス目が与えられます。 マス目の色は白か黒です。
すべてのマスが黒色になるまで、以下の操作を繰り返し行います。

辺を共有して隣接するマスの中に、黒色のマスが一つ以上存在するような白色のマスすべてが黒色になる。

何回の操作を行うことになるか求めてください。 ただし、最初に与えられるマス目には少なくとも 1 つ黒色のマスが存在します。

入力
H W
‘#’,’.’ からなる W 文字の文字列が H 行

(ただし 1 ≦ H, W ≦ 1000)
‘.’ : そのマスの色は白であることを表す。
‘#’ : そのマスの色は黒であることを表す。

これも幅優先探索なのですが、開始点が複数あります。そこでまずは複数ある開始点の座標を取得し、それをQueueに格納します。あとはほとんど同じですが、すべてのマスを探索するに要した回数を答えなければなりません。ここでは次に探索する座標だけでなく、これまでの探索回数もQueueに格納することにしました。これで回数を数えることができます。