どの行が何をしているかをつかめば、空欄は3つとも決まります。
難易度 ★(当サイトの目安)── 説明文の(1)〜(3)を while と if に写すだけ。4段階の決め方は科目B 最短合格の戦略にあります。
出題
出典:基本情報技術者試験 科目B サンプル問題 問4
次のプログラム中の a ~ c に入れる正しい答えの組合せを,解答群の中から選べ。
関数gcd は,引数で与えられた二つの正の整数num1 とnum2 の最大公約数を,次の(1)~(3) の性質を利用して求める。
(1) num1 とnum2 が等しいとき,num1 とnum2 の最大公約数はnum1 である。
(2) num1 がnum2 より大きいとき,num1 とnum2 の最大公約数は,(num1 - num2) とnum2 の最大公約数と等しい。
(3) num2 がnum1 より大きいとき,num1 とnum2 の最大公約数は,(num2 - num1) とnum1 の最大公約数と等しい。
〔プログラム〕
○整数型: gcd(整数型: num1, 整数型: num2) 整数型: x ← num1 整数型: y ← num2 a if ( b ) x ← x - y else y ← y - x endif c return x
解答群
ア a = if (x ≠ y) / b = x < y / c = endif
イ a = if (x ≠ y) / b = x > y / c = endif
ウ a = while (x ≠ y) / b = x < y / c = endwhile
エ a = while (x ≠ y) / b = x > y / c = endwhile
※ 解答群の原本は a・b・c を3つの列に分けた表です。当サイトでは1行にまとめて引用しました(字句は変えていません)。
答えだけ先に見る
正解は エ(a = while (x ≠ y)/b = x > y/c = endwhile)です。
この問題に出てくる記号
読めない記号があったときだけ開いてください。
擬似言語の記号 5コ の読み方をひらく
| 書き方 | 読み方 |
|---|---|
整数型: x ← num1 |
整数の箱 x を用意して、num1 の値を入れる |
x ← x - y |
x から y を引いた値で、x を上書きする |
if (…) / else / endif |
かっこの中が真なら上を、偽なら else の下を、1回だけ実行する |
while (…) / endwhile |
かっこの中が真のあいだ、あいだの行を何度でもくり返す。偽になったら endwhile の次へ |
x ≠ y |
x と y が等しくないとき真 |
コードは何をしているか ── 3つの性質が、コードのどこにあるか
見えている行が、問題文の性質(1)〜(3)のどれにあたるかを結びつけます。
○整数型: gcd(整数型: num1, 整数型: num2)
2つの正の整数を受け取る
整数型: x ← num1
num1・num2 を x・y に写す。以後は x・y がその役を引き継ぐ
整数型: y ← num2
a
?
if ( b )
?
x ← x - y
性質(2) x から y を引く = (num1 - num2) の形
else
y ← y - x
性質(3) y から x を引く = (num2 - num1) の形
endif
c
?
return x
性質(1) 等しいなら、x が答え
※ 右側の注釈は当サイトで書き加えたものです。プログラム自体は原文のまま引用しています。
関数 gcd が返すのは x です。だから、最後の x が最大公約数になっていなければなりません。そして性質(2)(3)のとおり、大きいほうから小さいほうを引いても、最大公約数は変わりません。つまりこのコードは、最大公約数を変えないまま引き算で2つの数を小さくしていき、x そのものが最大公約数になったところで返します。空欄で決めるのは、引き算の4行を何回実行するか(a・c)と、どちらが大きいときに x から引くか(b)です。
空欄 a と c を決める ── 1回引いたら終わりか
〔プログラム〕空欄 a〜c のまわり(上の〔プログラム〕から抜き出した。1字も変えていない)
整数型: y ← num2 a if ( b ) x ← x - y else y ← y - x endif c return x
※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。
return x が最大公約数になるのは、性質(1)のx と y が等しいときだけです。15 と 6 なら、9 と 6 → 3 と 6 → 3 と 3 と、3回引いてやっと等しくなります。だから、等しくなるまで引き算をくり返します。
もし a が if (x ≠ y) だったら
琥珀=書き換わった変数
15 と 6 で1回だけ引いて、そのまま return x(b は x > y のままとする)
前
x15
y6
後
x9
y6
if は1回だけ。9 と 6 のまま endif を抜けて、9 を返してしまいます。6 は 9 で割り切れないので、9 は最大公約数ではありません。b が逆向きでも、if なら1回で終わるのは同じです。
条件が真のあいだくり返すのが while です。a = while (x ≠ y)、c = endwhile。
空欄 b を決める ── どちらから引くか
〔プログラム〕空欄 b の if(上の〔プログラム〕から抜き出した。1字も変えていない)
if ( b )
x ← x - y
else
y ← y - x
endif
※ 上の〔プログラム〕からの抜粋です(1字も変えていません)。
b が真のときに実行するのは x ← x - y。性質(2)の引き算で、使えるのは「num1 がnum2 より大きいとき」です。だから b = x > y。
もし b が x < y だったら
琥珀=書き換わった変数
15 < 6 は偽 → else で y から x を引く(a は while (x ≠ y) のままとする)
y ← y - x
前
x15
y6
後
x15
y-9
小さいほうから大きいほうを引いて、6 - 15 = -9。次も 15 < -9 は偽なので、y は -24、-39 … と減り続け、x と y は等しくならず、くり返しが終わりません(答えが返りません)。
解答群を見る
a = while (x ≠ y)、b = x > y、c = endwhile。この組は エ です。
答え合わせ
正解は エ です。
ア・イは if なので1回で終わり、ウは向きが逆で終わりません。エを入れて gcd(15, 6) を最後まで動かすと、3 が返ります。
1行ずつ追う 正解の エ で gcd(15, 6)
出典:科目B サンプル問題 問4(空欄に エ を入れたもの)
ループ開始前
いま計算していること
変数の状態
return で返した値
トレース表(進めると1行ずつ積み上がります)
次に読む
この問題でどこに手間取ったかで、行き先が変わります。
この記事で引用した資料
いずれも独立行政法人情報処理推進機構(IPA)が公表したものです。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。

