平成30年秋期試験午後問題 問9

午前試験免除制度対応!基本情報技術者試験のeラーニング【独習ゼミ】

問9 ソフトウェア開発(C)

次のCプログラムの説明及びプログラムを読んで,設問1~3に答えよ。

 本問は,図1に示す路線構成の鉄道模型における列車の運行をシミュレーションするプログラムである。表1は,図1の説明である。
pm09_1.png
〔列車を進行させるルール〕
  • 各列車は,あらかじめ決められた始発駅から,あらかじめ決められた終着駅を行先として,路線を後戻りすることなく進行する。
  • 一つの区間には,同時に一つの列車しかいることができない。
  • 各区間の入口には信号機があり,赤又は緑を表示する。
  • 各列車は,終着駅を出口とする区間にいるときは無条件に進行できる。終着駅を出口とする区間にいる列車が進行した場合,その列車は路線上から取り除かれる。
  • 各列車は,現在いる区間の出口で接続する区間(以下,次区間という)が次の条件をいずれも満たしたとき,次区間に進行できる。
    1. 次区間の信号機の表示が緑である。
    2. 次区間に進行すると,最終的には行先とする終着駅に到達できる。
  • 次の二つの処理を繰り返し実行して各列車を進行させる。
    1. 路線を構成する全ての区間の信号機それぞれについて,区間内に列車がいるときは表示を赤に,列車がいないときは表示を緑にする。
    2. 路線を構成する全ての区間それぞれについて,次の処理を行う。
      (ア) 終着駅を出口とする区間に列車がいる場合は,(4)に従って列車を進行させ,路線上から取り除く。
      (イ) (ア)で述べた以外の区間に列車がいる場合は,(5)に従って進行できる列車を進行させ,進行した区間の信号機の表示を赤にする。

〔プログラム1の説明〕
  • 構造体 block_info は,鉄道模型の区間を表現する。
    pm09_2.png
    train:
    区間内にいる列車を表現した,構造体 train_info へのポインタである。区間内に列車がいないとき,NULLを設定する。
    next:
    次区間を表現した,構造体 block_info へのポインタを格納する配列(配列の大きさは2)である。終着駅を出口とする区間では,いずれの要素にもNULLを設定する。次区間が一つしかなければ,そのポインタは最初の要素に設定し,2番目の要素にはNULLを設定する。
    signal:
    信号機に表示する色を示す。次のいずれかの定数値をとる。
    RED  表示は赤
    GREEN 表示は緑
  • 構造体 train_info は,鉄道模型の列車を表現する。
    pm09_3.png
    number:
    列車の番号である。
    dest:
    列車の終着駅を出口とする区間を表現した,構造体 block_info へのポインタである。
  • 関数 set_signals の仕様は,次のとおりである。
    機能:
    全ての区間の信号機それぞれについて,区間内に列車がいるときは表示を赤に,列車がいないときは表示を緑にする。
    引数:
    blocks 全ての区間を表現した,構造体 block_info の配列
    nblock blocks の要素数
pm09_4.png

設問1

プログラム1中の に入れる正しい答えを,解答群の中から選べ。
a に関する解答群
  • block->next[0]->train == NULL
  • block->next[1]->train == NULL
  • block->next[0]->train == NULL || block->next[1]->train == NULL
  • block->next[0]->train == NULL && block->next[1]->train == NULL
  • block->signal == RED
  • block->train == NULL
  • block->train != NULL
解答選択欄
  • a:
  • a=

解説

aについて〕
set_signals は、全ての区間の信号機の表示を緑または赤にする関数です。分岐処理を見ると、[a]が真のときに、区間(block)の信号(signal)を緑にし、elseの処理として、区間の信号を赤にしているので、[a]には信号の表示を判断するための条件式が入るとわかります。

〔列車を進行させるルール〕(6)の①に「路線を構成する全ての区間の信号機それぞれについて,区間内に列車がいるときは表示を赤に,列車がいないときは表示を緑にする」とあります。[a]が真のときは緑を表示したいので、[a]には「自区間内に列車が存在しない」という条件式が入ることになります。

〔プログラム1〕の説明に「区間内にいる列車を表現した,構造体 train_info へのポインタである。区間内に列車がいないとき,NULLを設定する」とあるように、区間内の列車の有無は、構造体 block_info のメンバーである train が保持しています。[a]の1つ上の行で、変数 block に現在の区間情報(block_infoの先頭アドレス)を格納しているので、この block を使って「block->train == NULL」という式を入れれば、真のときに緑に、偽のときに赤にという分岐処理を実現できます。

a=カ:block->train

設問2

関数 proceed は,進行できる全ての列車を進行させるプログラムである。プログラム2中の に入れる正しい答えを,解答群の中から選べ。

(プログラム2の説明〕
  • 関数 proceed の仕様は,次のとおりである。
    機能:
    全ての区間それぞれについて,進行できる列車がいるかどうかを判定し,進行できると判定された列車を進行させる。終着駅を出口とする区間にいる列車を進行させた場合,その列車を路線上から取り除く。出口で他の区間と接続する区間にいる列車を進行させた場合,進行した区間の信号機の表示を赤にする。
    引数:
    blocks 全ての区間を表現した,構造体 block_info の配列
    nblocks blocksの要素数
  • 関数 proceed から呼び出される関数 find_block の仕様は,次のとおりである。
    機能:
    引数 block で示す区間が,引数 dest で示す区間に最終的に到達できる経路上にあるかどうかを判定する。
    引数:
    block 判定対象の区間を表現した,構造体 block_info へのポインタ
    dest 列車の終着駅を出口とする区間を表現した,構造体 block_info へのポインタ
    返却値:
    到達できるとき,1
    到達できないとき,0
pm09_5.png
b に関する解答群
  • block->train->dest == NULL
  • block->train->dest != NULL
  • block == block->train->dest
  • block != block->train->dest
c に関する解答群
  • break
  • continue
  • return
d に関する解答群
  • dest, block
  • dest, block->next[i]
  • block, dest
  • block, block->next[i]
  • block->next[i], dest
  • block->next[i], block
解答選択欄
  • b:
  • c:
  • d:
  • b=
  • c=
  • d=

解説

bについて〕
if文内の処理より、tain に null を代入していることから、区間(block)の列車を取り除いていることわかります。問題文の〔列車を進行させるルール〕より、区間から列車がなくなるパターンは以下の2つのパターンです。
  • 区間が終着駅であるとき列車が進行した場合
  • 区間内の列車が次の区間に進んだとき
if文内の処理は、無条件に列車を取り除くだけで、区間内の列車を次の区間に進める処理が記述されていません。問題文にある、終着駅の区間にいる列車は無条件に進行でき、その列車は区間から取り除かれるという説明から、この処理は現在の区間が列車の終着駅である場合に行う処理であると考えられます。

〔プログラム1〕の train_info の説明にあるように、列車の目的地は train_info 構造体のメンバーである dest が保持しています。現在参照している区間は block が保持しているため、両者(のアドレス)が同じならば列車が終着駅の区間に到達していると判断できます。

b=ウ:block == block->train->dest

cについて〕
まず初めに、関数 proceed 内の for (j=0; j<2; j++) について解説をします。for文内の処理は大きく分けて3つの部分で構成されています。
pm09_7.png
これは、行き先区間を決定するためのループになります。今回の問題の場合、区間の行き先(区間の出口で接続する区間)は多くても2通りです(図1を参照)。したがって、このfor文では next[0] と next[1] に対して以下の2点を確認し処理しています。
  • どちらの区間に行くべきか。
  • 進むべき区間は赤信号ではないか。
[c]のif文が実行されるのは、関数 find_block の結果が1の場合です。関数 find_block が1の場合とは、次の区間(block->next[j])が終着駅(block->train->dest)への経路上、若しくは終着駅の区間そのものに当たるときです。if文の内部では行き先の区間に列車を進めることを含め3つの処理を行っています。
pm09_8.png
もし、区間(block)内の列車を進めた場合、再度for文を実行する必要がなくなります。例えば、block->next[0] に列車を進めた場合、block->next[1] に列車が進めるかどうかを確認する必要はありません。これより、[c]にはfor文を抜ける処理が該当することがわかります。よって、正解は「break」になります。

なお、continue にすると次のループを実行してしまう(書いても書かなくても処理に変化がない)ため、return にすると現在の区間で関数 proceed 自体が終了してしまうため誤りです。単純に消去法で正解も導くことも可能です。

c=ア:break

dについて〕
find_block は、引数 block の区間が、引数 dest の区間に最終的に到達できるかどうかを判定する関数です。

block の先に dest があるかどうかを判定するためには、block の次の区間を再帰的に探す必要があります。つまり、block の次の区間(block->next[i])が dest と一致するかどうかを考え、一致しない場合は、さらにその次の区間が dest と一致するかどうかを考えることを繰り返します。第1引数は、現在の block の次の区間を表す式を指定すればよいため block->next[i]、第2引数は終着駅を指定するため dest となります。

例として、図1の路線構成において区間3と区間6が繋がっているか判定することを考えると、find_block は次のように呼び出されます。
find_block(区間3, 区間6)
 //next[0]=区間4を確認する
 find_block(区間4, 区間6)
  //next[0]=区間5を確認する
  find_block(区間5, 区間6)
  //next[1]=区間6を確認する
  find_block(区間6, 区間6) //1を返す
d=オ:block->next[i], dest

設問3

図1に示した鉄道模型の路線構成及び列車位置を表現した,構造体 block_info の配列を第1引数とし,その要素数9を第2引数として,プログラム3を実行した。プログラム3の実行が終了したときの状態について述べた次の記述中の に入れる正しい答えを,解答群の中から選べ。ここで,blocks[n] は区間 n を示す。
pm09_6.png
 列車4がいるのは区間eである。また,区間eの出口で接続する区間はf
e に関する解答群
  • 0
  • 2
  • 3
  • 7
f に関する解答群
  • 一つあり,その信号機は緑を表示している
  • 一つあり,その信号機は赤を表示している
  • 二つあり,それらの信号機はいずれも緑を表示している
  • 二つあり,それらの信号機はいずれも赤を表示している
  • 二つあり,それらの信号機は,一方が緑を,もう一方が赤を表示している
解答選択欄
  • e:
  • f:
  • e=
  • f=

解説

eについて〕
〔プログラム3〕では関数 proceed を4回実行しているので、図1の路線構成を見ながら処理をトレースしていきます。proceed のfor文は「区間8→区間7→…→区間0」というように、数が大きい区間から数が小さい区間の順に処理していくことに注意しましょう。

[関数 proceed 1回目]
区間8の列車0が取り除かれます。
区間4の列車1が区間5に進みます。
区間3の列車2は区間4に進めません(列車はいないが赤信号)。
区間1の列車3が区間2に進みます。
区間0の列車4は区間2に進めません(列車3がいる)。
pm09_9.png
[関数 proceed 2回目]
区間5の列車1が取り除かれます。
区間3の列車2が区間4に進みます。
区間2の列車3は区間3に進めません(列車はいないが赤信号)。
区間0の列車4は区間2に進めません(列車3がいる)。
pm09_10.png
[関数 proceed 3回目]
区間4の列車2が区間6に進みます。
区間2の列車3が区間6に進みます。
区間0の列車4は区間2に進めません(列車はいないが赤信号)。
pm09_11.png
[関数 proceed 4回目]
区間6の列車2が取り除かれます。
区間3の列車3が区間4に進みます。
区間0の列車4が区間2に進みます。
pm09_12.png
〔プログラム3〕終了後に列車4がいるのは区間2です。したがって「イ」が正解です。

e=イ:2

fについて〕
区間2の出口で接続する区間は、区間3の1つだけです。〔プログラム3〕終了後の区間3には列車が存在しないので、set_signals により緑信号が表示されます。したがって「ア」の記述が適切です。

f=ア:一つあり,その信号機は緑を表示している

Pagetop