見出し画像

「情報関係基礎」過去問を教材化する:2013年・営業時間の設定

 2013年度の問題は,ある飲食店の営業時間を見直すという題材。
この問題には,2012年度の問題と共通することがある。それは「説明されている内容をきちんと理解しようとすると時間がかかる」ということだ。「なぜそうなるのか」をわかってから進もうとすると,おそらく制限時間内には解けない。「なぜそうなるか」は置いといて,「そう書いてあるから」で進めば時間内には正解にたどり着く。とはいえ,それではできないものも含まれているので,2012年度の問題よりは難しいといえるだろう。
 何が難しいかというと,番号を表す変数と対応する配列の要素の関係の把握だ。生徒はこの手のものに弱い。たとえば
・数列 a_n で,a_k の次の項は? に a_(k+1) と答えられない。
・階差数列 b_n = a_(n+1)-a_n が苦手
・漸化式が苦手

ということを頭に入れて,問題を見ていこう。実際の問題はWeb上にあるから(簡単に見つかる)それを見てもらうことにして要点だけ示す。

ある店の時間帯別の一日あたりの利益が表1のようになっている。

画像1

営業時間内の利益の和を総利益とし,これが最大となるように営業時間を決める。
以下,時間帯 i の開始時間から時間帯 j の終了時刻までの総利益を【 i , j 】と書くことにする。この【 i , j 】を手作業で求め,表2を作成した。すると,【 3 , 7 】=28 が最大値なので,この店の時間帯を3から7まで,すなわち,8時から23時とすればよいことがわかった。アイ・ウエ・オ に適する数を答えよ。

画像2

これをプログラムで求められるようにした。(図1)
表1の時間帯別の利益は配列 Rieki に格納されている。
求まった営業時間の最初と最後の時間帯を 変数 kaisi , syuryo に,そのときの総利益を変数 saidaiRieki に格納する。
ク〜スに適するものを選択肢から選びなさい。また,サの比較が行われる回数を求めなさい。(選択肢は略)

画像3

ここまでが問1。難しくはない。
次が問2だが,あとの説明のために,ところどころに point の番号を入れてある。

問2
 Rさんは表2において,【1,3】〜【1,8】 がそれぞれ【3,3】〜【3,8】より2だけ小さいのは【1,-2】=-2 が理由であることに気がついた。同じように,【6,6】〜【6,8】がそれぞれ【3,6】〜【3,8】より8だけ小さいのは【3,5】=8が理由である。 (※point 1)
 一般的には,i ≦ j < k とするとき,【 i , k 】=【 i, j 】+【 j+1, k 】から次がわかる。 (※point2)
(1) 【 i, j 】≧ 0 のとき,【 i , k 】≧【 j+1, k】なので,【 j+1, k 】を計算する必要はない。
(2) 【 i, j 】< 0 のとき,【 i , k 】<【 j+1, k】なので,【 i, k 】を計算する必要はない。  (※point3)
 これらの性質を利用すれば,表2の(セ)などは計算しなくても,総利益の最大値を求めることができる。この考えにもとづいて,図1の手続きを改良しよう。
 上の(1)から,計算中の総利益が0以上である間は,終了時間帯を次にずらして総利益を求める。(2)から,計算中の総利益が負になった場合には,そのときの終了時間帯の次を開示時間帯に設定して先を調べていく。 (※point4)
この考えに基づき,表1に対する処理過程を示すと,下の表3のようになる。

画像5

この考えにしたがって次のプログラムを作った。(セ の選択肢のみ示す)

画像6

      =====================
(セ)〜(ツテ)は後回しにして,先にプログラムの中を考えよう。
表1の利益を合計していくのが総利益なので,ナは soRieki + Rieki[j] になる。
「もし(サ)ならば」は,(point3) の(1) の場合と考えてよい。したがって始めのプログラムと同じ i と j だ。
「そうでなくもし soRieki<0 ならば」は(point3)の(2) に該当し,(point4)の「計算中の総利益が負になった場合には,そのときの終了時間帯を次の開示時間帯に設定して」から,i = j + 1 とすればよいことがわかる(ネ)。このとき,総利益は計算し直すので,soRieki=0 とする(ヌ)

 では,パスしておいた(セ)〜(ツテ)はどうなるだろう。(セ)の選択肢は6つある。どう判断すればいいだろうか。
 まずここで止まってしまう生徒がかなり出ると思われる。プログラムは,説明文の意味を考えずとも,「こうすればよい」で答えが出る。しかし,この(セ)は,説明文の意味を理解して,一つ一つチェックする必要があるからだ。表2を始めから見ていこう。(再掲)そのために使用する point3 も再掲しておく。

画像7

(1) 【 i, j 】≧ 0 のとき,【 i , k 】≧【 j+1, k】なので,【 j+1, k 】を計算する必要はない。
(2) 【 i, j 】< 0 のとき,【 i , k 】<【 j+1, k】なので,【 i, k 】を計算する必要はない。  (※point3)

まず,【1, 1】≧ 0 なので,(point3)の(1)から,j=1 より【2,k】( 1 < k )は計算しなくてよい。i = 2 のところは計算しないので斜線を引いておこう。(水色)
次に【1 , 2】= -2 なので,(point3)の(2)から【1, k】は計算しなくてよい。(紫) 次は,ここまでに計算しないところは飛ばして,【3, 3】に進む。(point3)の(1)から,【4,k】は計算しなくてよい。(オレンジ) 次に【3, 4】に進み同様に【5,k】は計算しなくてよい。(緑) 次に【3, 5】に進み,【6,k】は計算せず,【3, 6】から【7,k】も計算せず,【3,7】から【8,k】も計算しない。
(赤) 

画像7

これで全部調べたので,選択肢中該当するのは,2つとも計算しなかった【1,4】と【6,7】である。すなわち④。
 ここは,一つずつ追っていく必要があるが,そのためには(point3)の(1) (2) が使えなくてはいけない。これができない生徒がかなりいそうである。「意味がわからない」のである。

 次に,表3の中のソ,タチ,ツテを考えよう。?を含めて全部埋めていく。

画像8

こんどは,point4の

計算中の総利益が0以上である間は,終了時間帯を次にずらして総利益を求める。(2)から,計算中の総利益が負になった場合には,そのときの終了時間帯の次を開示時間帯に設定して先を調べていく

を使う。
まず(b)。(a)で「計算中の総利益が0以上」なので,終了時間帯をずらして2になっている。開始時間は変えないので1。総利益は -2 である
次の(c)。(b)で総利益が負になったので,開始時間帯は「その時の終了時間帯の次」の3にする(ソ)。 以下,順に追っていくと(ツテ)は12,(タチ)は20 になる。

画像9

 以上,条件を見ながら順に追っていく,という作業をするのだが,書かれていることの意味がわからないと追っていけない。 i , j , k で混乱する生徒は結構いるだろう。

 これで一応は答えられた。
実際にはもう一つ,プログラム中の(サ)の比較を何回行うかという設問がある。表3を見れば 8 とわかるが,プログラムを追っていこうとすると意外に厄介だ。

 はじめに書いたことに戻る。「「なぜそうなるのか」をわかってから進もうとすると,おそらく制限時間内には解けない」と書いた。
具体的に行こう。

Rさんは表2において,【1,3】〜【1,8】 がそれぞれ【3,3】〜【3,8】より2だけ小さいのは【1,-2】=-2 が理由であることに気がついた。

となっているが,なぜ? なぜ【1,-2】= -2 だと【1,3】〜【1,8】 は【3,3】〜【3,8】より2だけ小さくなるのか。確かにそうなっているから,問題を解く上ではそれでいいが,あらためて「なぜ」と聞かれたときに答えられるだろうか。

答えは,【1,3】〜【1,8】は【1,-2】の -2 に3からあとの利益を足していくのに対し,【3,3】〜【3,8】は,0に3からあとの利益を足していくから である。
次の,

【6,6】〜【6,8】がそれぞれ【3,6】〜【3,8】より8だけ小さいのは【3,5】=8が理由である

も,「【3,6】〜【3,8】が【6,6】〜【6,8】より8だけ大きい」と表現を変えれば,【3, k 】は【3,5】の8に足していくからである。
 これを一般化したのが(point3)の(1)(2)なのだが,ここでも聞こう。

 一般的には,i ≦ j < k とするとき,【 i , k 】=【 i, j 】+【 j+1, k 】から次がわかる。 (※point2)
(1) 【 i, j 】≧ 0 のとき,【 i , k 】≧【 j+1, k】なので,【 j+1, k 】を計算する必要はない。
(2) 【 i, j 】< 0 のとき,【 i , k 】<【 j+1, k】なので,【 i, k 】を計算する必要はない。  (※point3)

まず,なぜ 【 i , k 】=【 i, j 】+【 j+1, k 】が成り立つのか。
「あたりまえ」ならそれで結構。i から k までの和は,i から j までの和と j から kまでの和を足したものだ。
次に,なぜ,「【 i, j 】≧ 0 のとき,【 i , k 】≧【 j+1, k】」なのか。
え? 簡単じゃんという人は,数学的な意味がわかっている人。
【 i , k 】=【 i, j 】+【 j+1, k 】なのだから,【 i, j 】≧ 0 なら,左辺の【i , j】は右辺にある【 j+1, k 】以上だ。
さて,この問いを生徒に投げ掛けたとき,何人が即答できるか,かなり心配である。「文字になっているとわからない(思考停止)」という生徒が結構いる。

さらに,なぜ「計算する必要はない」のか,と問うたらどうだろう。
答えは,「最大値を求めようとしているのだから小さかったら対象外だから」だ。

∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞

 以上,この問題を教材として取り上げるとなると,ただ演習問題としてやらせて答え合わせでよいかどうか,おおいに疑問である。上っ面だけ読んで解答して終わり,となりかねない。上に示した問いを交えながら問題の解釈をしていく授業を行ったほうがいい。コーディングはそのあと。そしてそのとき,「エッ,これがわからないのか」ということになるということを覚悟しておくべきだ。
 こういうことは,こういった演習問題をやらせて「エッと思った」経験によるものであり,経験のない人には到底想像がつかないことだろう。

では,Pythonを使ったプログラム例を載せておこう。
問1では,表2に相当する結果も書き出すようにした。ただし,桁合わせは面倒なので,表2と形式は合わない。数値を確かめるだけである。サの比較回数もカウントしている。

jikantai = list(range(9))
jikan = ['', '2-5', '5-8', '8-11', '11-14', '14-17', '17-20', '20-23', '23-2']
Rieki = ['', 1, -3, 2, 10, -4, 12, 8, -4]
saidaiRieki = 0
count = 0
for i in range(1, 9):
   soRieki = 0
   for j in range(i, 9):
       soRieki = soRieki + Rieki[j]
       count += 1
       if soRieki > saidaiRieki:
           saidaiRieki = soRieki
           kaisi = i
           syuryo = j
       print(soRieki, end=' ')
   print('')
print('開始時間帯は ', kaisi, 'とし')
print('終了時間帯は ', syuryo, 'とする。')
print('総利益の最大値は ', saidaiRieki, '千円である。')
print('サ の比較回数は ', count, '回')

次に問2。表3に該当する結果と,比較回数も表示している。

jikantai = list(range(9))
jikan = ['', '2-5', '5-8', '8-11', '11-14', '14-17', '17-20', '20-23', '23-2']
Rieki = ['', 1, -3, 2, 10, -4, 12, 8, -4]
saidaiRieki = 0
soRieki = 0
i = 1
count = 0
for j in range(i, 9):
   soRieki = soRieki + Rieki[j]
   print('開始時間帯 ', i)
   print('終了時間帯 ', j)
   print('総利益 ', soRieki)
   count += 1
   if soRieki > saidaiRieki:
       saidaiRieki = soRieki
       kaisi = i
       syuryo = j
   elif soRieki < 0:
       soRieki = 0
       i = j + 1
   print('総利益の最大値 ', saidaiRieki)
   print('-----------------')
print('サ の比較回数は ', count, '回')

結果の表示も含めて教材化するなら,元の問題の空欄の他に,print 文のどこかを適当に空欄にするか,問2では,難しくはなるが,print文を示して,適する箇所に挿入させてもいいだろう。

【追記】この note を見たひと(Twitter:「Ф一」(なかのひと)@jnsgsec
さん)から,問題作成部会のコメントのリンク先をがあることを教えていただいた。

(セ)の正答率が低いことをはじめ,この note で書いたことと一致しているのではないかと思われる。すなわち,意味がわからなくても書いてある通りにやればコードは書けるが,意味がわからなければ(セ)は正答できないということだ。