戦国IT - 情報処理技術者試験の過去問対策サイト
ブログお知らせお問い合わせ料金プラン

応用情報技術者 2013年 春期 午前207


問題文

配列Aに対して次の手続を実行して,2≦k≦100である素数だけを全て出力したい。a, b, cに入るループの初期値、終値、増分として、適切な組合せはどれか。   for k = 2 to 100 step 1:    A[k] = 1; for m = 2 to 10 step 1:    for k = [ a ] to [ b ] step [ c ]:       A[k] = 0; for k = 2 to 100 step 1:    if A[k] ≠ 0:       print k;
応用情報技術者 2013年 春期 午前2 問07の選択肢の画像

選択肢

(正解)

🔒 解説は解答すると表示されます

エラトステネスの篩のループ設定【午前2解説】

正解の理由

選択肢 (a=2m、b=100、c=m)は、各 m に対して m の倍数だけを 2m から 100 まで隔たり m ごとに正しく消去します。外側ループは m を 2 から 10()まで回しているため、100 以下の合成数は少なくとも一つの小さい素因数 m によって消去されます。したがって、最終的に A[k] が 0 でない k は素数のみ残り、目的どおり 2≦k≦100 の素数を出力できます。
(補足)内側ループの初期値を にするのが効率的な実装として一般的ですが、初期値を にしても動作的には正しく、ただし小さい倍数に対する重複除去が多くなり非効率になります。ここでは与えられた選択肢の中で「正しく動作する組合せ」を選ぶと が適合します。

解法ステップ

  1. 目的を確認:配列 A に対して合成数(素数でない数)を 0 にして、最終的に A[k] ≠ 0 の k を素数として出力する。
  2. 内側ループの増分 c は「m の倍数だけを消す」ので c = m が必須。
  3. 内側ループの終値 b は全体の上限 100 を超えないように b = 100 が自然(b が小さいと高い k を除去できない)。
  4. 内側ループの始点 a は「素数 m 自身を消さない」かつ「m の倍数を全てカバーする」位置であること。
    • a = m は最初の反復で k = m となり、素数 m を消してしまうため不可。
    • a = 2m は k = 2m, 3m, ... と進み、m 自身は含まれないので正しい(ただし効率面で m^2 の方が望ましい)。
  5. 上の条件から a=2m、b=100、c=m(選択肢 )が妥当と判断。

選択肢別の誤答解説

  • ア(a=2、b=m²、c=1)
    内側ループが step 1 で 2 から まで順に消すため、例えば m=2 のとき k=2 が消されて素数 2 を消してしまいます。また step 1 は m の倍数のみを消す意図に反し、非該当の数(素数含む)まで消去してしまいます。よって不適。
  • イ(a=2m、b=100、c=m)
    各 m について 2m, 3m, ... を 100 まで消去し、m 自身は消さない。外側を としてあるので 100 以下の合成数は必ずどれかの m によって消去され、正しく動作します。したがって正解。
  • ウ(a=m、b=m²、c=m)
    内側ループの初期値が a=m のため、k の最初の値が m になり A[m]=0 として素数 m 自体を消してしまいます(例えば m=3 のとき k=3 が最初に来る)。これが決定的な誤りです。なお b=m² を終値にする設計は効率化の観点では有益ですが、a が m だと致命的に不適です。
  • エ(a=m²、b=100、c=1)
    c=1 によって m² から 100 までの全ての数を順に消去してしまい、m² 以上の多くの素数まで消されます。特に m=2 の初回で 4 から 100 をすべて消すため大半の数が消えてしまい目的を満たさない設計です。

よくある誤解

  • 「始点は必ず 2m」:動作としては 2m でも正しいが、効率的実装では を始点にするのが一般的。 より小さい m の倍数は既に小さい素因数で消去済みだからです。
  • 「a = m にしても大丈夫」:a = m にすると最初の k が m になり素数 m 自体を消してしまう点を見落としやすい。
  • 「終値は m² で十分」:終値を m² にすると高い k(例:m が小さいときの大きな合成数)を消し残す可能性があるため、上限(ここでは 100)を終値にするか、内側ループの回数設定を工夫する必要がある。

補足コラム

効率的なエラトステネスの篩の実装では、内側ループを a = mm、c = m、b = N(配列上限)とすることが多いです。理由は、ある合成数 x が最小の素因数 p を持つとき、x = p * q であり q ≥ p なので x ≥ p^2 です。したがって p より小さい素数での処理によって pq のうち p*q < p^2 のものは既に消されているため、p 自身から p^2 未満の倍数を再度走査する必要はありません。これにより実行回数が大幅に削減され、全体の計算量は実用的には 程度になります。
参考実装(Python):
def sieve(n):
    A = [True] * (n+1)
    A[0] = A[1] = False
    m = 2
    while m*m <= n:
        if A[m]:
            for k in range(m*m, n+1, m):  # a = m*m が効率的
                A[k] = False
        m += 1
    return [i for i, isprime in enumerate(A) if isprime]
print(sieve(100))

FAQ

Q1: なぜ外側ループは 2 から 10()まででよいのですか?
A1: 任意の合成数 ≤100 は少なくとも一つの素因数 ≤√100 を持つため、√N までの素因数で十分に消去できます。
Q2: 実装上は 2m と m^2 のどちらを選べばよいですか?
A2: 両方とも正しくは動きますが、効率を考えると a = が推奨されます。教育的には 2m と書くことも多いので、選択肢の中身と目的(正しさか効率か)を確認してください。
Q3: c(増分)が m である必然性は?
A3: 目的は「m の倍数だけを消す」ことなので、増分は m(m, 2m, 3m, ...)でなければなりません。増分が 1 だと倍数以外も消してしまいます。

関連キーワード: エラトステネスの篩、素数探索、ループ設計、アルゴリズム最適化、計算量分析
← 前の問題へこの年度をクイズで解く次の問題へ →
戦国ITクイズ機能

\ せっかくなら /

応用情報技術者
クイズ形式で学習しませんか?

クイズ画面へ遷移する

すぐに利用可能!

©︎2026 情報処理技術者試験対策アプリ

このサイトについてブログプライバシーポリシー利用規約特商法表記開発者について