令和4年度 秋期 応用情報技術者試験 午後 問3 再帰とスタックによる迷路探索のトレース

学習ガイド

始点から終点までの経路を全て見つける迷路探索を、足跡フラグとスタックを使った再帰関数で実装する問題です。4方向の試行順序と“進む”“戻る”の定義に従って探索を手作業でたどり、スタックの内容や移動回数を数える練習を通じて、関数visitの穴埋めと複数解の探索を理解します。

この記事で押さえる論点

  • 足跡フラグと4方向の試行順序に従って“進む”“戻る”を手で追い、移動回数とスタックの内容を数えられる
  • 関数visitの空欄(解の記録・スタックの操作・迷路図情報の参照)を、探索手順の説明と対応付けて埋められる
  • 一つ目の解が見つかった後に探索を続ける仕組み(終点から戻る)を理解し、二つ目の解までの移動回数と訪問回数を求められる
  • 再帰呼出しの引数がどの座標を基点にするかを、戻る動作と結び付けて説明できる

問題本文

迷路の探索処理に関する次の記述を読んで,設問に答えよ。

始点と終点を任意の場所に設定する nimesmn imes m の 2次元のマスの並びから成る迷路の解を求める問題を考える。本問の迷路では次の条件で解を見つける。

  • 迷路内には障害物のマスがあり,nimesmn imes m のマスを囲む外壁のマスがある。障害物と外壁のマスを通ることはできない。
  • 任意のマスから,そのマスに隣接し,通ることのできるマスに移動できる。迷路の解とは,この移動の繰返しで始点から終点にたどり着くまでのマスの並びである。ただし,迷路の解では同じマスを 2回以上通ることはできない。
  • 始点と終点は異なるマスに設定されている。

5imes55 imes 5 の迷路の例を示す。解が一つの迷路の例を図1に,解が複数(四つ)ある迷路の例を図2に示す。

図1 解が一つの迷路の例
図の説明テキスト

7×7マスのグリッドで表された迷路の図。x軸、y軸ともに0〜6の座標が振られている。外周のマス(x=0,6, y=0,6)は斜線で塗られ「外壁」を表す。内部の5×5マスのうち(1,1)が「始点」、(5,5)が「終点」として示されている。一部のマスが灰色に塗られ「障害物」として配置されている。下部に「注記」として外壁と障害物の凡例があり、「図1 解が一つの迷路の例」というキャプションが付与されている。

図2 解が複数ある迷路の例
図の説明テキスト

図1と同様の形式の7×7マスの迷路の図。外周は外壁、(1,1)が「始点」、(5,5)が「終点」。障害物(灰色マス)の配置が図1とは異なり、始点から終点への経路の分岐が生じる構造になっている。下部に「図2 解が複数ある迷路の例」というキャプションが付与されている。

〔迷路の解を見つける探索〕

迷路の解を全て見つける探索の方法を次のように考える。

迷路と外壁の各マスの位置を x座標と y座標で表し,各マスについてそのマスに関する情報(以下,マス情報という)を考える。与えられた迷路に対して,障害物と外壁のマス情報には NGフラグを,それ以外のマス情報には OKフラグをそれぞれ設定する。マス情報全体を迷路図情報という。

探索する際の“移動”には,“進む”と“戻る”の二つの動作がある。“進む”は,現在いるマスから① y座標を1増やす,② x座標を1増やす,③ y座標を1減らす,④ x座標を1減らす,のいずれかの方向に動くことである。マスに“進む”と同時にそのマスのマス情報に足跡フラグを入れる。足跡フラグが入ったマスには“進む”ことはできない。“戻る”は,今いるマスから“進んで”きた一つ前のマスに動くことである。マスに“移動”したとき,移動先のマスを“訪問”したという。

探索は,始点のマスのマス情報に足跡フラグを入れ,始点のマスを“訪問”したマスとして,始点のマスから開始する。現在いるマスから次のマスに“進む”試みを①〜④の順に行い,もし試みた方向のマスに“進む”ことができないならば,次の方向に“進む”ことを試みる。4方向いずれにも“進む”ことができないときには,現在いるマスのマス情報をOKフラグに戻し,一つ前のマスに“戻る”。これを終点に到達するまで繰り返す。終点に到達したとき,始点から終点まで“進む”ことでたどってきたマスの並びが迷路の解の一つとなる。

迷路の解を見つけた後も,他の解を見つけるために,終点から一つ前のマスに“戻り”,迷路の探索を続け,全ての探索を行ったら終了する。迷路を探索している間,それまでの経過をスタックに格納しておく。終点にたどり着いた時点でスタックの内容を順番にたどると,それが解の一つになる。

図1の迷路では,始点から始めて,(1, 1)→(1, 2)→(1, 3)→(1, 4)→(1, 5)→(2, 5)→(1, 5)→(1, 4)のように“移動”する。ここまででマスの“移動”は7回起きていて,このときスタックには経過を示す4個の座標が格納されている。さらに探索を続けて,始めから13回目の“移動”が終了した時点では,スタックには ア 個の座標が格納されている。

〔迷路の解を全て求めて表示するプログラム〕

迷路の解を全て求めて表示するプログラムを考える。プログラム中で使用する主な変数,定数及び配列を表1に示す。配列の添字は全て0から始まり,要素の初期値は全て0とする。迷路を探索してマスを“移動”する関数 visitのプログラムを図3に,メインプログラムを図4に示す。メインプログラム中の変数及び配列は大域変数とする。

表1 プログラム中で使用する主な変数、定数及び配列
図の説明テキスト

表1 プログラム中で使用する主な変数、定数及び配列

名称 種類 内容
maze[x][y] 配列 迷路図情報を格納する2次元配列
OK 定数 OKフラグ
NG 定数 NGフラグ
VISITED 定数 足跡フラグ
start_x 変数 始点のx座標
start_y 変数 始点のy座標
goal_x 変数 終点のx座標
goal_y 変数 終点のy座標
stack_visit[k] 配列 それまでの経過を格納するスタック
stack_top 変数 スタックポインタ
sol_num 変数 見つけた解の総数
paths[u][v] 配列 迷路の全ての解の座標を格納する2次元配列。添字のuは解の番号、添字のvは解を構成する座標の順番である。
図3 関数 visit のプログラム
図の説明テキスト

関数 visit(x, y) の処理内容を示す擬似コードが枠で囲まれている。コード内には空欄 イ、ウ、エ があり、一部の行には「//足跡フラグを入れる」等のコメントが付与されている。

図4 メインプログラム
図の説明テキスト

「図4 メインプログラム」の擬似コード。function main で始まり、stack_topとsol_numの初期化、迷路図情報の設定、始点と終点の設定、visit(start_x, start_y)の呼び出しを行う。その後、空欄 オ が0と等しいかの条件分岐があり、条件に応じて結果の印字を行う処理が記述されている。

〔解が複数ある迷路〕

図2は解が複数ある迷路の例で,一つ目の解が見つかった後に,他の解を見つけるために,迷路の探索を続ける。一つ目の解が見つかった後で,最初に実行される関数 visit の引数の値は カ である。この引数の座標を基点として二つ目の解が見つかるまでに,マスの“移動”は キ 回起き,その間に座標が (4, 2) のマスは ク 回“訪問”される。

設問と解答・解説

設問1

(1)配点 2点

図1の例で終点に到達したときに,この探索で“訪問”されなかったマスの総数を,障害物と外壁のマスを除き答えよ。

模範解答

3

解説

迷路探索において再帰関数を用いた深さ優先探索(DFS)の挙動をトレースする問題です。

図1の例において、始点から終点に到達するまでに探索関数が呼び出され、訪問状態になったマスをたどります。

障害物と外壁を除いた空きマスのうち、終点到達時点で訪問されなかったマスの数を数えます。

探索順序に従いシミュレーションを行うと、最終的に訪問を免れたマスの数は 3 となります。

(2)配点 2点

本文中の ア に入れる適切な数値を答えよ。

模範解答

2

解説

本文中の文脈から、探索の条件や状態変化に関する数値を読み取る問題です。

再帰呼び出しのルールや変数の更新条件をトレースすることで、2 という値が導かれます。

設問2

図3中の イ 〜 エ に入れる適切な字句を答えよ。

(1)配点 2点

図3中の イ に入れる適切な字句を答えよ。

模範解答

paths[sol_num][k]

採点基準

正確性(内容)2点
  • 2点: 「paths[sol_num][k]」と正しく解答されている。
  • 1点: 解答の大部分は合っているが、インデックスの指定などに一部誤りがある。
  • 0点: 無解答、または全く異なる解答である。

解説

再帰関数内で見つかった解(経路)を保存する処理に関する空欄です。

見つかった経路の各ステップの座標を配列に記録します。

解の番号を表す変数とステップ数を表す変数を用いて、正しく paths[sol_num][k] に座標を代入するのが適切です。

高得点のポイント

  • 解を管理する配列のインデックス指定が正確であること。

  • 複数の解とステップ数を区別する変数を正しく用いていること。

(2)配点 2点

図3中の ウ に入れる適切な字句を答えよ。

模範解答

stack_top - 1

採点基準

正確性(内容)2点
  • 2点: 「stack_top - 1」と正しく解答されている。
  • 1点: スタック変数の指定は合っているが、演算子などに不完全な箇所がある。
  • 0点: 無解答、または全く異なる解答である。

解説

探索処理におけるスタックポインタの操作に関する空欄です。

再帰呼び出しから戻る際(バックトラック時)には、現在のマスを探索経路から外す必要があります。

そのため、スタックトップの値を1つ減らす stack_top - 1 が適切です。

高得点のポイント

  • バックトラック処理におけるスタックポインタの更新を正しく理解していること。

  • マイナス1の演算が正確に記述されていること。

(3)配点 2点

図3中の エ に入れる適切な字句を答えよ。

模範解答

maze[x][y]

採点基準

正確性(内容)2点
  • 2点: 「maze[x][y]」と正しく解答されている。
  • 1点: 配列名は合っているが、座標の指定などに不完全な箇所がある。
  • 0点: 無解答、または全く異なる解答である。

解説

迷路の現在のマス目の状態を判定する処理に関する空欄です。

探索を進める条件として、現在の座標が障害物や外壁ではない空きマスであることを確認する必要があります。

配列を用いて maze[x][y] の値を参照し、条件判定に用います。

高得点のポイント

  • 迷路の状態を保持する2次元配列から現在の座標を指定する方法を正しく理解していること。

設問3

配点 3点

図4中の オ に入れる適切な字句を答えよ。

模範解答

sol_num

採点基準

正確性(内容)3点
  • 3点: 「sol_num」と正しく解答されている。
  • 1点: 変数名に軽微なスペルミスがある等、解を保持する変数であることは読み取れるが完全ではない。
  • 0点: 無解答、または全く異なる解答である。

解説

見つかった解の総数を出力、または管理する処理に関する空欄です。

探索が終了した時点で、発見された解の数は変数 sol_num に格納されています。

これを出力することで、すべての経路を正しく列挙したことになります。

高得点のポイント

  • 解の総数を保持している変数の役割を的確に把握していること。

設問4

〔解が複数ある迷路〕について答えよ。

(1)配点 3点

本文中の カ に入れる適切な引数を答えよ。

模範解答

5,3

採点基準

正確性(内容)3点
  • 3点: 「5,3」と正しく解答されている。
  • 1点: 解答の一部が合っているが、片方の座標が誤っているなど不完全である。
  • 0点: 無解答、または全く異なる解答である。

解説

解が複数ある迷路の探索において、一つ目の解が見つかった後のバックトラック動作を問う問題です。

解説にもある通り、座標 (5,5)(5, 5) に到達して一つ目の解を見つけた後、関数は呼び出し元である (5,4)(5, 4) に戻ります。

そこから次の関数実行での引数は x=5x = 5、y=3y = 3 となります。

したがって、引数として 5,3 が適切です。

高得点のポイント

  • 再帰関数におけるバックトラックの挙動を正確にトレースできること。

  • 直前の呼び出し元に戻った後、次にどの座標に探索が進むかを理解していること。

(2)配点 2点

本文中の キ に入れる適切な数値を答えよ。

模範解答

22

解説

解が複数ある迷路において、全体の探索処理で再帰関数が呼び出された総回数やステップ数を問う問題です。

再帰関数は進めるマスがある限り呼び出され、行き止まりや解の発見で戻ります。

すべての経路を探索し尽くすまでの呼び出し回数を丁寧にトレースして数えると 22 となります。

どちらの方向にも進めなかった場合、呼び出し元の関数に戻るという再帰の性質を正しく読み取ることが重要です。

(3)配点 2点

本文中の ク に入れる適切な数値を答えよ。

模範解答

3

解説

探索の過程で特定の条件を満たした数値を問う問題です。

問題の条件に従って迷路全体の探索木を描き、該当する事象が起きた回数を数えると 3 になります。

設問4(1)は,正答率がやや低かった。一つ目の解が見つかった後のプログラム動作を理解できていないと思われる誤った解答が多く,終点や始点などの解答も見受けられた。座標(5,5)に達した後,呼出し元の(5,4)に戻り,次の関数実行での引数はx=5,y=3となることを理解してほしい。 設問4(2)キとクは,正答率が低かった。どちらの方向にも進めなかった場合,呼出し元の関数に戻る再帰関数となっていることを読み取って,動きを再現すればよいことを理解してほしい。

Spineチーム