令和6年度 秋期 応用情報技術者試験 午後問題 問3 エラトステネスの篩と計算量の改善

テクノロジアルゴリズム基礎理論

この問題は2024(R6)秋 応用情報技術者 午後に出題されたものです。出題時点の法令・制度に基づく内容のため、現行の内容と一致しない場合があります。

本ページの問題文・選択肢は、原本の体裁を Web 表示用に正規化しています(改行・記号・数式・図表参照の調整)。設問の趣旨および正解に影響する変更は加えていません。

学習ガイド

素数列挙アルゴリズムを段階的に改良していくプログラム穴埋め問題です。単純な試し割りからエラトステネスの篩へ、さらに平方数からの篩い落としへと3つの関数が並び、それぞれの実行回数を数えさせることで改良の意味を体感させる構成になっています。空欄の式を埋めるだけでなく、なぜその式で計算量が減るのかまで説明できることを目標に読み進めてください。

この記事で押さえる論点

  • エラトステネスの篩の動作をプログラムの穴埋めとして再現できる
  • 3つの実装の実行回数を数え、効率化の効果を定量的に比較する
  • 擬似言語の穴埋めで前後のループ条件から答えを絞り込む手順を身に付ける

問題本文

問3 素数を列挙するアルゴリズムに関する次の記述を読んで,設問に答えよ。

素数とは,2以上の自然数のうち,正の約数が1と自身だけである数のことである。2以上の自然数Nに対して,N以下の素数を列挙する関数prime1のプログラムを図1に示す。なお,本問では,配列の要素番号は1から始まり,要素数が0の配列を{}で表す。

図1 関数prime1のプログラム
図の説明テキスト

関数prime1のプログラム(擬似コード)。
○整数型の配列: prime1(整数型: N)
整数型の配列: primes ← {}
論理型: isPrime
整数型: d ← 2
整数型: t
/* メイン処理開始 /
while (d が N 以下)
isPrime ← true
t ← 2
while (t が d 未満)
if (d mod t が 0 と等しい)
isPrime ← false
endif
t ← t + 1 (L1)
endwhile
if (isPrime が true と等しい)
primes の末尾に d の値を追加する
endif
d ← d + 1
endwhile
/
メイン処理終了 */
return primes

この関数prime1の時間計算量は,Nを用いて表すと O( ) である。

〔アルゴリズムの改良1〕

素数の定義によって,2以上の自然数sについて,s自身を除くsの正の倍数uは,1とu以外にsも約数に含むので素数ではない。この性質を利用して関数prime1を改良し,次の手順で素数を列挙する関数prime2を考える。

(1) 2以上N以下の自然数について,全て“素数である”とマークする。
(2) 2以上N以下の自然数 d について,次の(a),(b)を行う。
(a) d が“素数ではない”とマークされている場合,何もしない。
(b) d が“素数である”とマークされている場合,次の処理を行う。
① d が素数であることを確定させる。
② d 以上の自然数 x について,d を x 倍した数を“素数ではない”とマークする。

関数 prime2 のプログラムを図2に示す。

図2 関数prime2のプログラム
図の説明テキスト

関数prime2のプログラム(擬似コード)。空欄イ、ウを含む。
○整数型の配列: prime2(整数型: N)
整数型の配列: primes ← {}
論理型の配列: isPrime ← {false}
整数型: c ← 2
整数型: d ← 2
整数型: t
while (c が N 以下)
isPrime の末尾に true を追加する
c ← c + 1
endwhile
/* メイン処理開始 /
while (d が N 以下)
if ( )
primes の末尾に d の値を追加する
t ← d × d
while (t が N 以下)
isPrime[t] ← false
t ← (L2)
endwhile
endif
d ← d + 1
endwhile
/
メイン処理終了 */
return primes

関数 prime2 は関数 prime1 と比較してメイン処理部の時間計算量を小さくすることができ,引数Nの値が同一の場合において,関数prime2の(L2)の行の実行回数は,関数prime1の(L1)の行の実行回数以下となる。

〔アルゴリズムの改良2〕

4以上の偶数は全て2の倍数であるので素数ではない。したがって,2以外の素数を列挙するためには奇数だけを考慮すればよい。この性質を利用して,関数prime2に次の変更を加えた関数prime3を考える。

(1) 関数の戻り値として素数の一覧が格納されるprimesにあらかじめ2を格納しておく。
(2) いずれのループも奇数についてだけ実行されるようにする。
(3) 3以上の自然数2k+1が素数か否かをisPrime[k]で表すようにする。

関数prime3のプログラムを図3に示す。

図3 関数prime3のプログラム
図の説明テキスト

関数prime3のプログラム(擬似コード)。空欄エ、オ、カを含む。
○整数型の配列: prime3(整数型: N)
整数型の配列: primes ← {2}
論理型の配列: isPrime ← {}
整数型: c ← 3
整数型: d ← 3
整数型: t
while (c が N 以下)
isPrime の末尾に true を追加する
c ← c + 2
endwhile
/* メイン処理開始 /
while (d が N 以下)
if ( )
primes の末尾に d の値を追加する
t ← d × d
while (t が N 以下)
isPrime[ ] ← false
t ← (L3)
endwhile
endif
d ← d + 2
endwhile
/
メイン処理終了 */
return primes

関数 prime3 は関数 prime2 と比較してメイン処理部の二重ループの実行回数を減らすことができる。引数 N の値が同一の場合において,関数 prime3 の(L3)の行の実行回数は,関数 prime2 の(L2)の行の実行回数の半分以下となる。加えて,計算に必要な配列 isPrime の要素数も半分以下に減らすことができる。

設問と解答・解説

設問1

本文中の に入れる適切な字句を答えよ。

模範解答

N^2

採点基準(配点 4点)

知識・理解度(内容)(2点)

  • 2: 素数の性質を利用したアルゴリズムの効率化手法を背景として、素朴な判定手法の計算量が対象に対してどのように増加するかを深く理解している。
  • 1: 計算量や変数の関係について部分的な理解が見られるものの、全体像の把握には至っていない。
  • 0: 効率化の背景に対する理解が不足しており、上記を満たさない。

論理性(構造)(2点)

  • 2: アルゴリズムの実行回数や計算量を示す適切な数式表現(N^2など)を用いて、論理的かつ正確に表現されている。
  • 1: 表現の意図は伝わるが、数式表現として軽微な記述の誤りや不完全な点がある。
  • 0: 記述が論理的ではなく、正答率が低かった傾向に見られるような根本的な表現の誤りがある。

解説

エラトステネスの篩などの素数判定アルゴリズムを評価する際、処理の効率(計算量)を考えることが重要です。

  • 素朴な判定アルゴリズム(prime1など)では、ある数 NN に対して 22 から N1N-1 まで試し割りを行うため、処理全体の手間は NN の2乗、すなわち N2N^2 に比例して増加します。
  • この計算量 N2N^2 を削減し、効率的に素数を求める手法としてエラトステネスの篩などが活用されます。

高得点のポイント

  • アルゴリズムの実行回数や計算量が NN に対してどのように増加するかを理解していること
  • 適切な数式表現(N2N^2)で簡潔に記述できていること

設問2

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

(1)

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

模範解答

isPrime[d]がtrueと等しい

採点基準(配点 2点)

知識・理解度(内容)(1点)

  • 1: 素数の性質を利用したアルゴリズムの効率化手法を理解し、素数判定のための配列「isPrime」の役割と対象変数を正しく把握できている。
  • 0: アルゴリズムにおける配列の役割の理解が不足している。

論理性(構造)(1点)

  • 1: アルゴリズムをプログラムとして適切に記述する能力が示され、条件式として「trueと等しい」という論理が構文的に正しく構成されている。
  • 0: プログラムとしての適切な記述能力が示されておらず、論理的な構成に誤りがある。

解説

エラトステネスの篩(prime2)において、素数を見つけた際にその倍数をふるい落とす処理を行います。

  • 配列 isPrime は、各インデックスの値が素数であるかどうかを true または false の論理値で保持しています。
  • 対象となる数 d が素数であるかを判定するためには、配列の要素 isPrime[d]true であるかを確認する必要があります。

高得点のポイント

  • 判定対象となる配列 isPrime とインデックス d を正しく指定できていること
  • 条件式として「trueと等しい」ことを論理的に記述できていること

(2)

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

模範解答

t+d

採点基準(配点 2点)

知識・理解度(内容)(1点)

  • 1: エラトステネスの篩の効率化手法を理解し、倍数を走査する際の変数の役割と加算の必要性を正しく把握できている。
  • 0: アルゴリズムにおける変数の役割の理解が不足している。

論理性(構造)(1点)

  • 1: アルゴリズムをプログラムとして適切に記述する能力が示され、次の倍数を求めるループ更新処理(t+dなど)が論理的に正しく構成されている。
  • 0: プログラムとしての適切な記述能力が示されておらず、論理的な構成に誤りがある。

解説

素数 d の倍数をふるい落とすためのループ更新処理です。

  • 変数 td の倍数を表すインデックスとして用いられます。
  • 現在の倍数 t に対して、次の倍数を求めるためには d を加算する必要があるため、更新式は t+d となります。

高得点のポイント

  • エラトステネスの篩における倍数の走査方法を理解していること
  • ループ内で次の倍数を求める加算処理(t+d)を正しく記述できていること

設問2は,正答率が高かった。アルゴリズムをプログラムとして適切に記述する能力を身につけることは重要である。

設問3

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

(1)

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

模範解答

isPrime[(d-1)÷2]がtrueと等しい

採点基準(配点 2点)

知識・理解度(内容)(1点)

  • 1: 素数の性質を利用した効率化の手法を理解し、奇数のみを扱う配列中のデータの保持方法を正しく把握できている。
  • 0: 配列中のデータの保持方法についての理解が不足している。

論理性(構造)(1点)

  • 1: 繰り返し実行されるループの中でカウンタ変数がどのように変化するかを注意深く考慮し、インデックス変換と条件判定がプログラムとして論理的に正しく構成されている。
  • 0: カウンタ変数の変化に対する考慮が不足しており、プログラムとしての論理的な構成に誤りがある。

解説

奇数のみを対象とした効率化アルゴリズム(prime3)における素数判定処理です。

  • 偶数(22 以外)は素数ではないため、奇数のみを配列に保持することでメモリと処理時間を節約できます。
  • 奇数 kk は、インデックス i=(k1)÷2i = (k-1) \div 2 に対応づけられます。
  • したがって、奇数 d が素数であるかを判定するには、isPrime[(d-1)÷2]true であるかを確認します。

高得点のポイント

  • 奇数のみを保持する配列のインデックス変換規則を正しく理解していること
  • プログラムの条件式として正確に記述できていること

(2)

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

模範解答

(t-1)÷2

採点基準(配点 2点)

知識・理解度(内容)(1点)

  • 1: 素数の性質を利用した効率化の手法を理解し、ふるい落とす対象の値を配列インデックスに変換するためのデータ保持方法を正しく把握できている。
  • 0: 配列中のデータの保持方法についての理解が不足している。

論理性(構造)(1点)

  • 1: 繰り返し実行されるループの中でカウンタ変数がどのように変化するかを注意深く考慮し、対象値を適切なインデックスに変換する数式が論理的に正しく構成されている。
  • 0: カウンタ変数の変化に対する考慮が不足しており、プログラムとしての論理的な構成に誤りがある。

解説

見つかった素数 d の倍数 t をふるい落とす際に、対象となる配列のインデックスを計算する処理です。

  • td の奇数倍であり、これもまた奇数です。
  • 奇数のみを管理する配列 isPrime において、奇数 t が格納されているインデックスは、変換規則に基づき (t-1)÷2 となります。

高得点のポイント

  • ふるい落とす対象の値 t を、対応する配列のインデックスへ変換する数式を理解していること
  • 括弧を用いた正しい演算順序で式を記述できていること

(3)

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

模範解答

t+2×d

採点基準(配点 2点)

知識・理解度(内容)(1点)

  • 1: 素数の性質を利用した効率化の手法を理解し、奇数倍のみを走査するために加算すべき値(2×d)の概念を正しく把握できている。
  • 0: 配列中のデータの保持方法や走査対象のステップ幅についての理解が不足している。

論理性(構造)(1点)

  • 1: 繰り返し実行されるループの中でカウンタ変数がどのように変化するかを注意深く考慮し、次の奇数倍へと進む更新処理がプログラムとして論理的に正しく構成されている。
  • 0: カウンタ変数の変化に対する考慮が不足しており、プログラムとしての論理的な構成に誤りがある。

解説

奇数のみを扱う効率化アルゴリズムにおいて、次のふるい落とし対象となる倍数を計算する処理です。

  • 素数 d (奇数)の倍数のうち、偶数倍はすでに除外されているため、奇数倍のみをたどる必要があります。
  • 現在の奇数倍 td を足すと偶数倍になってしまうため、2×d を足して次の奇数倍へと進めます。
  • したがって、更新式は t+2×d となります。

高得点のポイント

  • 奇数の奇数倍のみを走査するためには、2×d ずつ加算する必要があるという数学的性質を理解していること
  • それをプログラムの更新式として正しく記述できていること

設問3は,正答率がやや低く,配列中のデータの保持方法についての理解が不足していると思われる解答が散見された。繰り返し実行されるループの中で,カウンタ変数がどのように変化するのかを注意深く考えてほしい。

設問4

prime1(20),prime2(20),prime3(20)をそれぞれ実行したとき,図1中の(L1)の行,図2中の(L2)の行,図3中の(L3)の行が実行される回数をそれぞれ答えよ。

(1)

図1中の(L1)の行が実行される回数を答えよ。

模範解答

171

配点 2

解説

関数 prime1(20) における素朴な素数判定処理のループ実行回数を求める問題です。

  • prime1 では、各整数 nn について、22 から n1n-1 までの数で割り切れるかを判定します。
  • n=2,3,4,,20n = 2, 3, 4, \dots, 20 について、内側のループ(行 L1)の実行回数はそれぞれ 0,1,2,,180, 1, 2, \dots, 18 回となります。
  • これらの合計を求めると、0+1+2++18=18×192=1710 + 1 + 2 + \dots + 18 = \frac{18 \times 19}{2} = 171 となり、実行回数は 171 回です。

各選択肢の解説

本問は数値による記述式解答であるため、固定の選択肢はありませんが、以下のような誤答が想定されます。

  • 境界値の誤り: ループの終了条件を nn までの包含として計算してしまった場合など、等差数列の項数を見誤る計算ミスに注意が必要です。

(2)

図2中の(L2)の行が実行される回数を答えよ。

模範解答

13

配点 2

解説

関数 prime2(20) (エラトステネスの篩)における倍数のふるい落とし処理(行 L2)の実行回数を求める問題です。

  • 素数 dd の倍数を t=d2t = d^2 から走査する最適化が適用されているものとします。(d=2d=2 の場合は t=4t=4
  • d=2d = 2 の場合:t=4,6,8,10,12,14,16,18,20t = 4, 6, 8, 10, 12, 14, 16, 18, 209回 実行されます。
  • d=3d = 3 の場合:t=32=9t = 3^2 = 9 から始まり、t=9,12,15,18t = 9, 12, 15, 184回 実行されます。
  • d=4d = 4 は素数でないためスキップされます。
  • d=5d = 5 の場合:t=52=25t = 5^2 = 25 となり、上限の 2020 を超えるため実行されません。
  • 合計すると、9+4=139 + 4 = 13 となり、実行回数は 13 回です。

各選択肢の解説

本問は数値による記述式解答であるため、固定の選択肢はありませんが、以下のような誤答が想定されます。

  • 開始位置の誤り: 最適化を考慮せず、すべての素数で t=2dt=2d から数えてしまうと、重複して実行回数を多く見積もる誤答につながります。

(3)

図3中の(L3)の行が実行される回数を答えよ。

模範解答

2

配点 2

解説

関数 prime3(20) における、奇数のみを対象としたふるい落とし処理(行 L3)の実行回数を求める問題です。

  • このアルゴリズムでは、22 を除く奇数(3,5,,193, 5, \dots, 19)のみを配列で管理します。
  • d=3d = 3 の場合:最適化により t=d2=9t = d^2 = 9 から始まり、2d=62d = 6 ずつ加算されます。対象となる tt9,159, 152回 のみです。(次は 2121 となり範囲外)
  • d=5d = 5 の場合:t=52=25t = 5^2 = 25 となり、開始時点で上限 2020 を超えるため実行されません。
  • 以降の奇数についても同様に実行されないため、全体の実行回数は 2 回となります。

各選択肢の解説

本問は数値による記述式解答であるため、固定の選択肢はありませんが、以下のような誤答が想定されます。

  • ステップ幅の誤り: 奇数倍のみをたどるための +2d+2d のステップ幅を見落とし、tt の増加を小さく見積もってしまう計算ミスに注意が必要です。