基本情報技術者 2011年 春期 午後 問09
次のCプログラムの説明及びプログラムを読んで、設問1,2に答えよ。
〔プログラム1の説明〕
U劇場の座席予約システムにおいて、希望する座席種別と座席数を指定すると、連続した空き(未予約)座席があるかどうかを調べるプログラムである。
(1) U劇場の座席配置は図1に示すとおりである。

① U劇場には、ステージ側から列名がA〜Zの26列の座席があり、各列の座席数は異なる。
② 各列の座席は、ステージに向かって一番左から順に1、2、…と数え、列名のA〜Zと、この数(以下、番という)を組み合わせた座席番号で識別される。例えば、“L列6番”の座席とは、12列目(L列)のステージに向かって一番左から6番目の座席を示す。
③ 各座席には、料金の違いを示す種別(以下、座席種別という)が割り振られている。座席種別は、料金が高いものから順にS、A、B、Cの四つがある。図1中の座席の文字は座席種別を表している。
(2) 空き座席を探すときには、ステージに向かって最前列の一番左(A列1番)から開始して、同一の列に希望する座席種別と座席数の連続した空きがあるかどうかを調べる。A列で見つからなかった場合は、順次B列、C列、…と後列を対象にして同様に調べる。
(3) 関数check_seatsの引数は次のとおりである。ここで、引数の値に誤りはないものとする。
class 希望の座席種別
num 希望の座席数
hall 座席表
pos 確認結果(POSITION型の構造体へのポインタ)
① 連続した空き座席が見つかった場合、最初に見つかった空きの中で、ステージに向かって一番左に位置する座席の座席番号をposが指す構造体に格納する。
② 連続した空き座席が見つからなかった場合、posが指す構造体の座席の列名にナル文字を格納する。
(4) 構造体SEATの構造は次のとおりである。
typedef struct {
char seat_class; /* 座席種別 */
int reserved; /* 予約状態 */
} SEAT;
(5) 構造体POSITIONの構造は次のとおりである。
typedef struct {
char seat_row; /* 座席の列名 */
int seat_no; /* 座席の番 */
} POSITION;
(6) 座席表hallの要素hall[i][j]はSEAT型の構造体であり、各座席の座席種別と予約状態が次のとおり格納されている。ここで、添字iの0〜25が列名A〜Zに、添字jの0〜Ni−1が番1〜Ni(Niは、添字iに対応する列の座席数)に対応している。
hall[i][j].seat_class:座席種別を表す“S”、“A”、“B”、“C”のいずれかの文字が格納されている。
hall[i][j].reserved:予約状態が格納されている。0は空きを、1は予約済を表す。
各列のステージに向かって一番右の座席の次の要素の座席種別hall[i][Ni].seat_classには、ナル文字が格納されている。

設問1:
問題文を見る プログラム1中のに入れる正しい答えを、解答群の中から選べ。
a, bに関する解答群
ア:cnt = 0
イ:cnt--
ウ:cnt++
エ:found = 0
オ:found = 1
c, dに関する解答群
ア:no
イ:no - num
ウ:no - num + 1
エ:no - num + 2
オ:row
カ:row + 1
キ:row_s[row]
ク:row_s[row + 1]
模範解答
a:オ、b:ア、c:キ、d:エ
解説
解答の導き方
このプログラムは、列をA列から順に調べ、希望する座席種別で空いている座席が連続している場所を探します。空き座席が途切れたら、連続数を数え直す必要があります。
まず、変数の役割を確認します。
- cnt:条件に合う空き座席が、今のところ何席連続しているかを数えます。
- found:希望する座席数が見つかったかどうかを表します。初期値は0です。
- row:列の位置を表します。0がA列、1がB列というように対応します。
- no:列の中の座席位置を表します。0が1番、1が2番というように対応します。
aには「見つかった」ことを記録する処理が入ります。
本文では、連続する空き座席数が希望数以上になったら、その場所を見つけたと判断します。その条件が成立したときに、外側の列を調べる処理にも見つかったことを伝える必要があります。foundの初期値が0で、後の処理が「found != 0」を見ているため、aにはfound = 1が入ります。
bには、連続数を0に戻す処理が入ります。
座席種別が希望と違う場合や、予約済みの場合は、連続した空き座席がそこで途切れます。そのため、次の座席から新たに数え始めるようにcnt = 0とします。cntを1だけ減らすのでは、途切れる前の連続数が残ってしまいます。
cには、見つかった列の列名を指定します。
rowは列名そのものではなく、列の位置を表す添字です。本文では、添字0〜25が列名A〜Zに対応すると説明されています。row_sには列名がAから順に入っているので、row番目の文字を取り出すrow_s[row] が適切です。
dには、連続した空き座席の先頭の座席番号を指定します。
noは、連続数が希望数に達した座席の添字です。添字は0から始まるため、座席番号より1小さい値です。
希望数をnumとすると、連続した空き座席の先頭の添字はno - num + 1です。さらに、添字を座席番号に直すために1を足します。したがって、座席番号はno - num + 2です。
例えば、numが3で、座席の添字4、5、6が連続して空いている場合、最後の座席の添字noは6です。先頭の座席番号は、6 - 3 + 2 = 5番になります。このため、dにはno - num + 2が入ります。
誤りやすいポイント
- 空き座席の連続数が途切れたとき、cntを1だけ減らすのではありません。 連続数は最初から数え直すので、0に戻します。
- foundを1にするのは、連続した空き座席が希望数に達したときです。 cntだけを更新しても、外側の列を調べる処理には見つかったことが伝わりません。
- rowは列名ではなく、0から始まる位置です。 列名を格納するには、row_sから対応する文字を取り出します。
- noは座席番号ではなく、0から始まる添字です。 最後の座席位置から先頭位置を求めた後、座席番号に直すための1を加える必要があります。
FAQ
Q: 座席種別が希望どおりでも、予約済みならcntは増えないのですか?
A: はい。座席種別が一致し、かつreservedが0のときだけ、空き座席として数えます。予約済みの座席があれば連続が途切れるため、cntは0に戻ります。
A: はい。座席種別が一致し、かつreservedが0のときだけ、空き座席として数えます。予約済みの座席があれば連続が途切れるため、cntは0に戻ります。
Q: なぜ希望数に達した後、内側の繰返しだけでなく外側の繰返しも終了するのですか?
A: 条件に合う場所が見つかった後に別の列も調べると、最初に見つかった座席ではなく、後から見つかった座席で結果が上書きされるおそれがあるためです。foundを確認して外側の繰返しも終了します。
A: 条件に合う場所が見つかった後に別の列も調べると、最初に見つかった座席ではなく、後から見つかった座席で結果が上書きされるおそれがあるためです。foundを確認して外側の繰返しも終了します。
Q: 座席が見つからなかった場合はどうなりますか?
A: foundが初期値の0のままなので、最後にpos->seat_rowにナル文字が格納されます。これは、希望に合う連続した空き座席が見つからなかったことを表します。
A: foundが初期値の0のままなので、最後にpos->seat_rowにナル文字が格納されます。これは、希望に合う連続した空き座席が見つからなかったことを表します。
関連キーワード: 配列、添字、ループ処理、条件分岐、番兵値
設問2:
問題文を見る 関数check_seatsを使って、希望する座席種別の連続した空き座席があるかどうかを調べ、その結果を出力する。希望する座席種別の連続した空き座席がない場合には、ほかの座席種別で希望する座席数の連続した空き座席があるかどうかを調べ、その結果を出力するプログラムを作成した。作成したプログラムに関する説明文中のに入れる正しい答えを、解答群の中から選べ。
(1) 関数check_serviceの引数は次のとおりである。ここで、引数の値に誤りはないものとする。
class 希望の座席種別
num 希望の座席数
hall 座席表
opt 結果の出力順
(2) 関数check_serviceで使用している関数print_seatsの仕様は次のとおりである。
void print_seats(char class, int num, POSITION *pos)
機能:指定の座席種別の連続した空き座席があるかどうかの確認結果を出力する。
引数:class 座席種別
num 座席数
pos 確認結果(POSITION型の構造体へのポインタ)


〔プログラム2の説明〕
(1) 希望する座席種別の連続した空き座席があるかどうかを調べ、その結果を出力する。
(2) 希望する座席種別の連続した空き座席がない場合には、希望する座席種別eに対して、結果の出力順optが0の場合は座席種別の料金がfものから順に、結果の出力順optが0以外の場合は座席種別の料金がgものから順に希望する座席数の連続した空きがあるかどうかを調べ、その結果を順次出力する。
eに関する解答群
ア:よりも料金の高いすべての座席種別
イ:よりも料金の安いすべての座席種別
ウ:よりも一つ料金の高い座席種別
エ:よりも一つ料金の安い座席種別
オ:を除くすべての座席種別
fに関する解答群
ア:高い
イ:安い
gに関する解答群
ア:高い
イ:安い
模範解答
e:オ、f:ア、g:イ
解説
解答の導き方
この設問では、希望する座席種別で空きが見つからなかったとき、ほかの座席種別をどの範囲・順番で調べるかを読み取ります。
-
最初に希望する座席種別を調べます。
関数check_serviceは、まずcheck_seatsで希望する座席種別の空きを調べ、その結果をprint_seatsで出力します。check_seatsで空きが見つからない場合、問題文のプログラム1の説明にあるとおり、posが指す構造体のseat_rowにはナル文字が格納されます。 -
希望する種別で見つからない場合だけ、別の種別を調べます。
その条件が「pos.seat_row == '\0'」です。つまり、最初の確認で空きが見つからなかった場合に、続けて別の座席種別を調べます。 -
希望する種別以外のすべてを調べます。
class_sには料金が高い順に「SABC」が格納されています。繰返し処理(同じ処理を順番に行う処理)の中では、class_sから座席種別を一つずつ取り出し、希望する種別と同じ場合は処理を飛ばします。
そのため、調べるのは希望する種別を除くすべての座席種別です。したがって、eには「を除くすべての座席種別」に当たるオが入ります。 -
optの値によって、調べる順番が変わります。
class_sは「SABC」の順です。問題文には、S、A、B、Cの順に料金が高いとあります。- optが0の場合は、class_s[i]を使うため、「SABC」の順です。料金が高いものから調べます。
- optが0以外の場合は、class_s[CLSNUM - i - 1]を使うため、「CBAS」の順です。料金が安いものから調べます。
したがって、fには「高い」に当たるア、gには「安い」に当たるイが入ります。
なお、別の座席種別を調べる繰返し処理には、空きが見つかったときに繰返しを抜ける処理がありません。そのため、希望する種別以外の種別を順番に確認し、その結果を出力します。
誤りやすいポイント
- 希望する種別に近い料金の種別だけを調べる、と考えないようにします。プログラムでは、希望する種別と同じものだけを飛ばし、それ以外を対象にしています。
- optが0以外の場合は、料金が高い順ではなく、料金が安い順です。class_sの参照位置が逆向きになるためです。
- 別の種別で空きが見つかったら、そこで確認を終えるとは限りません。プログラムには繰返しを途中で終える処理がありません。
FAQ
Q: 希望する種別も、別の種別を調べる処理で再び確認しますか?
A: いいえ。if (class != c)の条件で、希望する種別と同じものは飛ばされます。
A: いいえ。if (class != c)の条件で、希望する種別と同じものは飛ばされます。
Q: optが0以外なら、どのような順番になりますか?
A: class_sを逆向きに参照するため、「CBAS」の順になります。料金の安いものから高いものへの順です。
A: class_sを逆向きに参照するため、「CBAS」の順になります。料金の安いものから高いものへの順です。
Q: ほかの種別で空きが見つかったら、残りの種別は調べませんか?
A: いいえ。繰返しを終了する処理がないので、希望する種別以外を順に確認します。
A: いいえ。繰返しを終了する処理がないので、希望する種別以外を順に確認します。
関連キーワード: 配列、条件分岐、繰返し処理、構造体



