冬期講習 2026-2027、募集中。総復習は売りません。90分×完全1対1で、穴だけを塞ぎます 詳しく →
電話 0422-27-7828チャットで質問無料相談を予約

武蔵野個別指導塾の特徴

高校情報I アルゴリズムの設計—入力と出力と終了条件を先に決めて手順を作る|武蔵野個別指導塾

学習のイメージ写真 武蔵野個別指導塾
X LINE Facebook

受付番号を配る手順を入力と出力の約束から組み立て、0人や用紙不足の場合にも結果と終了条件を確かめます。

よくあるのは、高校生が例の一つが動けば完成と判断する場面です。受付に3人来たときに番号を3枚出せても、0人ならどうするか、人数が不正なら何を返すかが決まっていなければ、別の入力で使える手順とは言い切れません。受付番号を順に配る仕事を題材に、約束から処理を作り、その約束に戻して結果を確かめます。

何を答える問題か

問いには少なくとも3つの形があります。第1に、文章から入力の条件と出力の形を読み取り、未決定の規則を補う形です。第2に、約束を満たす手順を作り、途中の状態と終了理由を説明する形です。第3に、動いた例と動かない例を照合し、約束か手順のどちらを修正するか判断する形です。いずれも、先に値を代入して追うだけでは、手順が何を保証するのか見落とします。

ここでの受付は、人数をまとめて受け取ってから番号の一覧を作るものとします。人の到着順の管理や実際の印刷装置の操作は含めません。人数が0以上の整数なら、先頭番号1から人数と同じ個数の番号を、1ずつ増やして返します。結果は整数のリストです。0人には空のリストを返します。負の値、小数、文字列、真偽値は人数として受け付けず、エラーを返します。真偽値を除くことも、入力の約束の一部です。

たとえば人数が2なら答えは [1, 2] です。2枚あり、最初が1で、隣り合う番号の差は1です。どれか1つが合うだけでは足りず、個数と順序の両方が必要です。入力と出力を決めたら、次に手順が有限回で止まることを確かめます。

約束を手順に変える

アルゴリズムは、目的を達成するために実行順序を定めた手順です。プログラムは、その手順を機械が実行できる形に書いたものです。入力の制約は手順が受け取る値の範囲、出力の条件は返す値が満たすべき性質です。終了条件は、いつ繰り返しを終えるかを決めます。エラーも出力側の約束に含めると、前提外の入力が来たときの扱いを調べられます。

図1のように、人数の検査を通ったものについて、番号を追加し、終わった一覧を返します。検査に失敗した場合は番号を作らずにエラーを返します。エラーは人数0の結果ではありません。空の一覧は正しい入力に対する成功結果なので、両者を混同すると受付がなかったのか入力が壊れていたのか区別できません。

図1 人数の検査から番号一覧を返すまでの関係

図1の各箱には別の責任があります。検査は入力が約束に合うか、繰り返しは必要な番号を過不足なく作るか、返却は結果の形式が約束どおりかを受け持ちます。入力が整数であることだけを確認しても、負の整数を許すかは別に決めなければなりません。逆に、出力に整数が入っていても順番が逆なら今回の約束を満たしません。

手順の成立を説明するには、開始時、繰り返しの途中、終了時を分けます。開始時の一覧は空で、すでに配った番号は0個です。途中では「一覧には1から作成済みの個数までが順に入る」という条件を保ちます。次の番号を1個追加すれば、その条件は追加後も保たれます。作成済みの個数は毎回1増え、人数に達したら終了するため、0以上の有限の整数を入力した場合、追加は人数回で終わります。終了時には個数も順序も約束を満たします。

この説明は実例の成功とは別のものです。実行試験は書き間違いや想定漏れを見つける助けになりますが、試した入力以外の正しさをそれだけで証明しません。逆に、手順の説明が正しくても、コードに書き写す際の誤りは実行で見つかることがあります。

基本例題: 3人への番号

人数3を入力したとき、返る整数のリストを求めます。人数は0以上の整数、番号は1から連続し、リストの先頭から受付順に並びます。手で考えると、1人目に1、2人目に2、3人目に3なので期待値は [1, 2, 3] です。3個という条件と最後が3であることも確かめます。

def numbers(n):
    if type(n) is not int or n < 0:
        raise ValueError("invalid count")
    result = []
    next_number = 1
    while next_number <= n:
        result.append(next_number)
        next_number = next_number + 1
    return result

print(numbers(3))

def の行は人数を受け取る手順に名前を付けます。次の条件は、型が整数そのものではない場合、または負の場合を検出します。bool はPythonでは整数型との関係があるため、ここでは type(n) is not int として真偽値も除きます。raise は不正を呼出し側へ知らせ、以降の番号作成には進みません。

result は作成した一覧で、最初は空です。next_number は次に追加する番号で、初めは1です。while は次の番号が人数以下である間だけ中を実行します。append で番号を末尾に加え、その後に次の番号を1増やします。条件が成り立たなくなったら return が一覧を返し、最後の print が呼出し結果を表示します。

図2のように、3回の追加で一覧は伸びます。図2の最後の次番号4は、一覧の中に追加される番号ではなく、次の判定に使う値です。4は3以下ではないので、4回目の追加をせずに終了します。

図2 3人に番号を配る途中の一覧と次の番号
追加前の次番号    追加後の一覧    更新後の次番号
1                 [1]             2
2                 [1, 2]          3
3                 [1, 2, 3]       4

Python 3.14.8で入力3を実行した結果は [1, 2, 3] です。手で並べた期待値と一致します。0を入力すると最初から1は0以下でないため、追加は0回で [] を返します。1なら1回追加して [1] を返します。これらは開始時に終了する場合と、1回だけ進む場合を調べる試験です。

条件を変えて手順を設計する

標準例題では、受付の最初の番号を1に固定せず、正の整数 start で指定します。人数 n は先ほどと同じ条件です。2つの入力は整数そのものでなければならず、start は1以上とします。返す一覧は start から1ずつ増える n 個の整数とし、不正入力は ValueError とします。start が7、人数が4なら、手で数えて [7, 8, 9, 10] です。4個の番号があり、最初が7、最後が10です。

def numbers_from(start, n):
    if type(start) is not int or type(n) is not int:
        raise ValueError("invalid input")
    if start < 1 or n < 0:
        raise ValueError("out of range")
    result = []
    used = 0
    while used < n:
        result.append(start + used)
        used = used + 1
    return result

print(numbers_from(7, 4))

最初の2つの判定は型と範囲を別々に確かめます。型の検査を先にするので、文字列を数値と比較して予期しない型のエラーになることも避けられます。used は追加済みの個数です。空の一覧と0から始め、used が人数より小さい間、開始番号に追加済み個数を足した番号を追加します。次に used を1増やし、最後に一覧を返します。4人では追加する値が7、8、9、10、used が順に1、2、3、4となります。Python 3.14.8の実際の出力も [7, 8, 9, 10] です。

途中の条件は「一覧には開始番号から連続する used 個が入る」です。開始時は0個なので成立し、1回の追加で次の番号が末尾に入るため保たれます。used は毎回1増え、有限の人数に達して止まります。0人でも開始番号の妥当性を検査するという約束です。人数が0だからといって、開始番号の不正を見逃す設計ではありません。

発展例題では番号を作る前に、用紙の残り枚数 capacity も受け取ります。3つとも整数そのものとし、開始番号は1以上、人数と残り枚数は0以上です。人数が残り枚数を超える場合は一覧を作らず ValueError を返します。足りる場合は先ほどと同じ一覧を返します。開始番号12、人数2、残り枚数3なら期待値は [12, 13] で、必要な2枚は3枚以内です。開始番号12、人数2、残り枚数1なら不足のエラーです。部分的に1枚だけ配ることは、この仕様では許しません。

def checked_numbers(start, n, capacity):
    if type(capacity) is not int or capacity < 0:
        raise ValueError("invalid capacity")
    if type(start) is not int or type(n) is not int:
        raise ValueError("invalid input")
    if start < 1 or n < 0:
        raise ValueError("out of range")
    if n > capacity:
        raise ValueError("insufficient paper")
    return numbers_from(start, n)

print(checked_numbers(12, 2, 3))

最初に残り枚数の型と範囲を確かめ、次に開始番号と人数の型、範囲を確かめます。その後に必要枚数と残り枚数を比較します。いずれかが不正なら例外を返し、正常な場合だけ先ほどの手順を呼び出し、その結果を返します。Python 3.14.8での出力は期待どおり [12, 13] でした。用紙の枚数が人数と等しい場合も足りるので成功します。なお、これは番号一覧の作成であり、実際に紙へ印刷できたことまでは保証しません。

失敗も結果として設計する

次の試験はPython 3.14.8で実施したものです。各行の期待と実際が一致しました。成功の4件と失敗の4件を同じ数だけ並べています。エラー名は呼出し側が受け取る種類であり、一覧を返したことを意味しません。

入力 start, n, capacity 期待 実際 調べる条件
5, 3, 4 [5, 6, 7] [5, 6, 7] 通常の3人
5, 0, 0 [] [] 0人と残り0枚
5, 1, 1 [5] [5] 1人と枚数の一致
5, 2, 2 [5, 6] [5, 6] 必要枚数ちょうど
5, -1, 4 ValueError ValueError 負の人数
5, “2”, 4 ValueError ValueError 壊れた型の入力
5, 3, 2 ValueError ValueError 用紙不足
0, 0, 0 ValueError ValueError 0人でも開始番号が不正

成功の各一覧は、指定した開始番号から連続し、人数と同じ個数です。失敗では、誤った人数を0人と読み替えず、不足時に部分的な一覧も返しません。失敗の検査は成功の検査に付け足す飾りではなく、受付側が結果を使うための約束です。

実際の印刷や保存を外部の道具へ頼むなら、一覧の作成と外部への受渡しを別の段階にします。外部の道具が例外を返す、応答が時間切れになる、成功の返事が壊れている、途中で接続が切れる、といった4通りに対しても、各道具の約束に合わせて失敗と記録する試験を用意します。正常に印刷できた、0枚の要求を受け付けた、1枚を出した、ちょうど残数分を出したという4通りの成功試験と対応させます。時間切れ後に実際に印刷された可能性を排除できない場合、無条件に再送すると重複が起こり得ます。結果を確認できる仕組みを別途決め、未確認のまま成功とも未実行とも断定しません。ここでは外部装置を実装していないため、この8通りは設計上の試験であり、実行済みの結果ではありません。

誤りを途中から直す

基本例題の条件を誤って next_number < n にすると、人数3では [1, 2] が返ります。条件が真の間に1と2は追加されますが、次番号3の判定で偽になり、3人目の番号が抜けます。図3のように、最後の番号を追加する前に止まることが原因です。出力の長さ2は人数3に足りません。

図3 最後の番号を除く誤条件と修正後の判定

図3の修正は条件を next_number <= n にすることです。3以下である3も追加し、次番号が4になったところで終了します。Python 3.14.8で誤条件を人数3に適用すると実際に [1, 2]、修正後は [1, 2, 3] でした。修正後は3人に3個を順に配れることまで確かめます。さらに0人、1人でも再実行すると、それぞれ []、[1] でした。1人のとき誤条件では空になるため、境界付近の試験も原因の発見に役立ちます。

別の誤りとして更新を忘れると、次番号は1のままで、人数が1以上なら条件が変わりません。無制限には実行せず、2回分の追跡で追加後も次番号が1のままと確認します。終了理由を説明できない手順は、最初の出力が期待どおりでも完成とは扱えません。

自分で設計する5問

各問の番号は整数で、開始番号は1以上、人数と残り枚数は0以上の整数です。リストは受付順に並べ、失敗時は ValueError と答えます。問題の入力は本文の例とは別にしています。

  1. 開始番号20、人数3、残り枚数5です。返るリストと、使用後に残る枚数を答えてください。
  2. 開始番号30、人数0、残り枚数6です。返るリストと、番号を追加する回数を答えてください。
  3. 開始番号40、人数1、残り枚数1です。返るリストと、追加後の used を答えてください。
  4. 開始番号50、人数4、残り枚数3です。返る結果と、その理由を答えてください。
  5. 開始番号60、人数が文字列 "2"、残り枚数8です。返る結果と、番号一覧の作成へ進むかを答えてください。

答えと照合

  1. [20, 21, 22]、残り2枚です。used は0から1、2、3と進み、3個を作ります。5枚から3枚を使うと2枚で、受付する3人に番号が1個ずつ対応します。
  2. []、0回です。最初の used は0で、人数0より小さくないので追加しません。0人に番号0個という条件に戻しても一致します。残り6枚は使いません。
  3. [40]、used は1です。1回追加した後に used が1となり、人数より小さくなくなります。1枚の用紙で1人分を出せます。
  4. ValueError です。4人分には4枚必要ですが、残りは3枚です。3個だけ返すと全員に配れないため、不足の判定で作成を始めません。
  5. ValueError で、作成へ進みません。文字列は整数そのものではないため、数値に変換して受け入れる仕様ではありません。残り枚数が足りるかを論じる前に型の条件で止まります。

Python 3.14.8で各入力を checked_numbers に渡した実際の結果は、順に [20, 21, 22]、[]、[40]、ValueError、ValueError です。残り枚数は入力の枚数から返った番号の個数を引いて別に照合しました。失敗の2問ではリストが返らないため、使用枚数を成功結果から計算しません。

覚えておくこと

入力の型と範囲、出力の形を先に決めます。
途中で保つ条件と、毎回変わる値を追います。
終了時に目的の個数と順序へ戻して照合します。
正常な場合と失敗する場合を両方試します。

説明が止まった場所を見直す

個別指導で確かめるなら、まず「3人なら3個」という答えから、0人の入力へ話を移します。空の一覧と入力エラーを同じものと説明した場合は、どちらが受付可能な入力なのか、結果を受け取る側の立場で言い直します。次に処理表で追加前の値と追加後の値を別の列にし、最後の番号を入れる判定がどの行かを指してもらいます。

終了の説明が「いつか止まる」だけなら、人数との差が1回ごとにどう変わるかを確認します。外部の道具を使う場合は、一覧が作れたことと実際に配れたことを分けて説明します。入力の約束から結果の確認までをつなげると、1つの例の成功を超えて、手順の適用できる範囲が見えてきます。

読んで終わりにするか、ここから変えるか。

武蔵境駅徒歩30秒、講師1人に生徒1人の完全1対1。授業のあいだ、先生は隣を離れません。いまの詰まりを、無料相談でそのまま話してください。

まず15分だけ電話で話したい方は、無料電話相談(15分)から。塾からお電話を差し上げます。

本気になった日が、入塾の日。

お子様の教育、迷ったら「丸投げ」してください。必ず、期待以上の結果で返します。武蔵野で育む、武蔵境で学ぶ。

電話は年中無休。365日、24時間、お電話可能。

チャットで質問チャット
無料相談を予約する 電話 0422-27-7828電話 LINE チャット
で質問