応用情報技術者 2019年 春期 午後 問03
券売機の注文の状態を判定するプログラムに関する次の記述を読んで、設問1〜3に答えよ。
T社では、U社が経営する飲食店の店舗に設置する券売機のシステムを開発している。U社が店舗で提供する商品には、丼物や定食などのメイン商品のほか、みそ汁やサラダなどのサイドメニューがある。
U社では、特定の種類の商品を組み合わせたものをセットメニューとし、単品で注文した場合よりも安く提供している。
〔食券購入時の要件〕
食券購入時の主な要件を図1に示す。

商品と分類の具体例を表1に示す。表1中のNは分類番号、Sはセットメニューへの適用可否、Oはオプションの指定に関する情報である。Sは1のものがセットメニューへの適用可の商品である。分類番号1〜3で、Oが0以外のものは、オプションの指定が必要であることを示し、Oの値は、分類番号4のOの値と対応している。オプションを指定する際には、Oの値が一致するオプションだけが選択できる。
↩設問3
↩設問3〔注文の状態の判定手順〕
券売機は、画面上で商品を選択するボタンが押されるたびに、商品の情報を蓄積する。そして、蓄積した商品の情報を用いて状態遷移を初期状態から評価し直し、注文の状態を判定する。状態の判定には図2の状態遷移図を用いる。初期状態は0である。表1のN、S、Oを左から順に並べた3桁の数をイベントコードと呼び、イベントコードの値によって状態の遷移先を制御する。
状態の判定処理では、商品の情報を入力された順に取得し、状態遷移図に基づいて状態遷移を評価する。例えば牛丼、大盛り、漬物を注文した場合、状態は0、1、2、4の順に遷移する。この場合、最後の状態が発券可の状態なので、発券ボタンを押すことができる。また、値引きのルールの条件を満たさないので、値引きはしない。
〔状態遷移表〕
状態遷移図をプログラムとして実装するためには、状態遷移図を状態遷移表にして取り扱う。注文の状態遷移表を表2に示す。表2は、状態番号とイベントコードの組合せの表であり、表の各マスには遷移先の状態番号と、遷移の際の値引きの金額が入る。
例えば、図2で状態が2のときに漬物の注文が入ると状態4に遷移し、値引きは発生しないので、表2では、状態番号が2でイベントコードが210のマスには4:0が入る。遷移後の状態が発券可の状態なので、発券ボタンを押すことができる。
〔券売機の注文の状態を判定するプログラム〕
券売機の注文の状態を判定するプログラム(以下、判定プログラムという)を作成した。判定プログラムは、画面上で商品を選択するボタンが押されるたびに実行される。注文の状態を判定する手順を図3に示す。判定プログラム中で利用する主な変数、定数及び関数を表3に示す。


設問1:状態遷移について、(1)、(2)に答えよ。
問題文を見る(1)鮭定食、野菜サラダ、ゴマドレッシング、みそ汁の順番で注文が入った場合の状態遷移について、図2の状態番号を使って遷移する順を答えよ。
模範解答
0,2,3,4,5
解説
解答の論理構成
- 初期状態は【問題文】で「初期状態は0」であると示されています。
- 1品目「鮭定食」のイベントコード
- 2品目「野菜サラダ」のイベントコード
- N=“2”, S=“1”, O=“2” で “212”。
- 表2の“状態番号2×イベントコード212”は “3:0”。
- よって “2→3” へ遷移します。
- 3品目「ゴマドレッシング」のイベントコード
- N=“4”, S=“0”, O=“2” で “402”。
- 表2の“状態番号3×イベントコード402”は “4:0”。
- よって “3→4” へ遷移します。
- 4品目「みそ汁」のイベントコード
- N=“3”, S=“1”, O=“0” で “310”。
- 表2の“状態番号4×イベントコード310”は “5:50”。
- よって “4→5” へ遷移し、ここで値引き“50”が適用されます。
- 以上より遷移順は “0,2,3,4,5” となり、模範解答と一致します。
誤りやすいポイント
- 「鮭定食」はO=“0” であるためイベントコードは “110”。「111」と誤記しやすいです。
- 「みそ汁」はS=“1”。S=“0”と誤ると “300” になり、表2では自己ループ “4:0” なので最終状態が誤ります。
- 「ゴマドレッシング」は分類4のためN=“4”。分類2と混同して “212” を選んでしまうミスが散見されます。
- 値引き“50”は状態4→5のときだけ加算される点を見落としやすく、状態遷移自体を誤る原因になります。
FAQ
Q: イベントコードはどの順に並べるのですか?
A: 【問題文】で「表1のN、S、Oを左から順に並べた3桁の数をイベントコード」と定義されています。必ずN→S→Oの順です。
A: 【問題文】で「表1のN、S、Oを左から順に並べた3桁の数をイベントコード」と定義されています。必ずN→S→Oの順です。
Q: 発券可否はどこで判定されるのですか?
A: 図3の手順(8)と表2の“発券可”列で判断します。本問では最終状態“5”で表2の発券可が“true”なので発券可能です。
A: 図3の手順(8)と表2の“発券可”列で判断します。本問では最終状態“5”で表2の発券可が“true”なので発券可能です。
Q: 値引きは複数回適用されますか?
A: 表2では“値引きの金額”が遷移ごとに設定されていますが、セット割引は条件を満たした最初の遷移(状態4→5, “5:50”)で一度だけ付与される実装です。
A: 表2では“値引きの金額”が遷移ごとに設定されていますが、セット割引は条件を満たした最初の遷移(状態4→5, “5:50”)で一度だけ付与される実装です。
関連キーワード: 状態遷移表, イベントコード, 割引計算, 有限オートマトン
設問1:状態遷移について、(1)、(2)に答えよ。
問題文を見る模範解答
ア:false
イ:3:0
解説
解答の論理構成
-
状態3の発券可否(ア)
-
状態4でイベントコード「212」が発生した際の遷移(イ)
- イベントコード「212」は表1のN=2、S=1、O=2、すなわち「サイドメニュー−1」かつ“オプション必須”の商品です。
- 図2を見ると、サイドメニュー−1でオプションが未指定のときは必ず状態「3」に遷移し、そこでオプション(イベントコード「402」など)を待つ設計になっています。
- すでに発券可能な状態「4」にいても、新たにオプション必須のサイドメニュー−1を追加すると再びオプション待ちの状態「3」に戻る必要があります。
- また、値引きはこの時点では発生しないので金額は0です。
- よって イ には3:0が入ります。
誤りやすいポイント
- 発券可否を図2の円の形ではなく表2の既存値だけで判断してしまい、状態「3」をtrueと誤記する。
- 「212」が図2の矢印に明示されていないため自己ループと勘違いし、4:0やE:0としてしまう。
- “オプション必須”の判定をOの値だけでなくSの値まで誤って読んでしまい、イベントコードを取り違える。
FAQ
Q: イベントコードはどのように作られますか?
A: 表1のN・S・Oを「左から順に並べた3桁の数」と問題文にあるとおりです。例えば“野菜サラダ”はN=2, S=1, O=2なのでイベントコードは「212」となります。
A: 表1のN・S・Oを「左から順に並べた3桁の数」と問題文にあるとおりです。例えば“野菜サラダ”はN=2, S=1, O=2なのでイベントコードは「212」となります。
Q: 状態3と状態4の違いは何ですか?
A: 状態3は「オプションが未指定の商品を含むため発券不可」、状態4は「すべての必須オプションが確定し発券可」の違いです。オプション必須の商品を追加すると4→3に戻る点がポイントです。
A: 状態3は「オプションが未指定の商品を含むため発券不可」、状態4は「すべての必須オプションが確定し発券可」の違いです。オプション必須の商品を追加すると4→3に戻る点がポイントです。
関連キーワード: 状態遷移表, イベントコード, ステートマシン, セットメニュー値引き
設問2:
問題文を見る模範解答
ウ:order[i].A
エ:order[i].N*100+order[i].S*10
オ:status_table[status][event_index].discount
カ:status_table[status][event_index].status
キ:acceptedがtrueに等しい
解説
解答の論理構成
-
[ウ]
-
[エ]
-
図3(3)は「注文された商品のイベントコードを算出する」。
-
問題文には「表1のN、S、Oを左から順に並べた3桁の数をイベントコードと呼び」とあるため、event_code = N×100 + S×10 + O
-
これをorder配列要素で表すと order[i].N*100+order[i].S*10 となり、末尾の + order[i].Oは既にプログラム行に固定で書かれているので、[エ] は order[i].N*100+order[i].S*10 です。
-
-
[オ]
- 図3(4)では「状態遷移の際の値引きの金額を取得」すると記されています。
- 表3には「status_table[stat][ev].discountで値引きの金額を参照」とあるので、[オ] は status_table[status][event_index].discount です。
-
[カ]
- 図3(5)は「…次の状態番号を取得して、状態番号を更新」。
- 表3には「status_table[stat][ev].statusで遷移先の状態番号を参照」と示されているため、[カ] は status_table[status][event_index].status です。
-
[キ]
- 図3(8)で「発券の可否を判定して、発券ボタンの状態を変化」とあります。
- 表3によれば発券可のフラグはstatus_table[stat][ACCEPT_INDEX].acceptに格納され、図4ではいったんacceptedへ代入されています。
- よって判定条件は acceptedがtrueに等しい となり、[キ] は acceptedがtrueに等しい です。
誤りやすいポイント
- イベントコードの組立順を逆にしやすい
「N、S、Oを左から順に並べた3桁」とあるため100,10の重みを付け忘れると誤答になります。 - event_codeとevent_indexの混同
get_event_index() で得るのは列インデックスであり、そのまま状態を更新できない点に注意が必要です。 - 発券可否の判定先
acceptフラグをstatus_tableから直接参照せず、一度acceptedへ格納しているのでif条件でstatus_tableを再参照してしまうミスが多発します。 - discount加算漏れ
サイドメニュー値引きは遷移表から取得する設計です。表から読む代わりに別ロジックで判定しようとすると整合が取れなくなります。
FAQ
Q: 発券可の状態は状態遷移表を直接見ても良いですか?
A: はい、列 ACCEPT_INDEX に true が入っている行が発券可です。ただしプログラムでは一旦 accepted ← status_table[status][ACCEPT_INDEX].accept へ代入してから判定します。
A: はい、列 ACCEPT_INDEX に true が入っている行が発券可です。ただしプログラムでは一旦 accepted ← status_table[status][ACCEPT_INDEX].accept へ代入してから判定します。
Q: [エ] で + order[i].Oを書かなくてよい理由は?
A: 図4中の行は event_code ← エ + order[i].0 となっており、末尾の + order[i].O は既に固定で存在します。[エ] には残りの 部分のみを記述します。
A: 図4中の行は event_code ← エ + order[i].0 となっており、末尾の + order[i].O は既に固定で存在します。[エ] には残りの 部分のみを記述します。
Q: 値引き額はいつ確定しますか?
A: 各商品処理時にstatus_tableから取得しdiscountに加算します。ループ後に合計割引額が確定しており、追加計算は不要です。
A: 各商品処理時にstatus_tableから取得しdiscountに加算します。ループ後に合計割引額が確定しており、追加計算は不要です。
関連キーワード: 状態遷移表, イベントコード, 値引き計算, 配列参照, 発券判定
設問3:
問題文を見る図4の判定プログラムについて、プログラムに変更を加えず、表1、2の内容を変更するだけで対応できる要件を解答群の中から二つ選び、記号で答えよ。
ここで、表1、2の内容について、業務運用中の変更は行わないものとする。
解答群
ア:12:00~14:00の間はランチタイムとし、鮭定食を一時的に提供しないようにする。
イ:オプションの指定が必須なメイン商品について、並、大盛り、特盛りのオプションの指定の後に、ご飯にかけるつゆの量について、普通、多め、少なめの指定ができるようにする。
ウ:サイドメニュー1とサイドメニュー2の商品で、セットメニューに組み込める商品を複数個ずつ注文したときに、値引きも複数回適用する。
エ:メイン商品にカレーを追加する。カレーには並、大盛りを指定できるが、特盛りは指定できない。
模範解答
イ、エ
解説
解答の導き方
結論:イ、エ
- 前提として押さえる点(問題文からの根拠)
- 判定処理は「イベントコードは、表1のN、S、Oを左から順に並べた3桁の数をイベントコードと呼び、イベントコードの値によって状態の遷移先を制御する」とある。つまり、どのボタン(商品・オプション)がどの遷移を引き起こすかは表1(商品のN,S,O,A)と表2(状態遷移表)の組合せで決まる。
- また「オプションを指定する際には、Oの値が一致するオプションだけが選択できる」とあるので、オプションの表示/選択制御はOの値(=オプショングループ)でまとまっている。
- 判定プログラム本体は状態遷移表(status_table)を参照して遷移と値引きを決め、表1, 表2の内容だけで挙動を変えられる部分が「メニュー項目」「オプションのグルーピング」「状態遷移/その時の値引き額」である。
以上から、「表1に商品・オプション行を追加/編集」「表2にイベントコード(列)や該当セルの遷移先・値引きを追加/編集」の範囲であれば、プログラム変更なしに挙動を変えられる可能性があることが分かります。以下、各選択肢をこの観点で検討します。
ア:12:00~14:00の間はランチタイムとし、鮭定食を一時的に提供しないようにする。
- 問題点:これは「時間帯」による動的な可否制御であり、実行時(券売機稼働中)に表示/非表示を切り替える必要がある。表1, 表2は静的データであり、問題文で「表1、2の内容について、業務運用中の変更は行わないものとする」と明記されているため、運用中に表を差し替えて対応することは不可である。
- また判定プログラム側に時刻を判断して可否を切る処理がないことから、時間条件での制御を行うにはプログラム(または運用プロセスでの表の差替え)を変更する必要がある。
→ よってアは表1, 表2だけでは対応できない。
イ:オプション必須なメイン商品について、並、大盛り、特盛りの指定後に、つゆ量(普通、多め、少なめ)を指定できるようにする。
-
実現可能性の根拠:「オプションを指定する際には、Oの値が一致するオプションだけが選択できる」「イベントコードはN,S,Oで決まる」なので、表1のO値を用いてオプション群を定義し、表2にそのイベントコード(例:N=4,S=0,O=新規の値 → 403等)の列を追加して遷移を定義すれば、プログラムを変えずに選択肢を増やしたり複数指定を可能にできる。具体的な手順(表のみの変更で完結)を示すと次の通り。実装方法(表だけで済ませる手順)
- 追加するオプション群をひとまとめにする新しいO値を決める(既存のO=1やO=2を流用すると既存商品にも影響するため、影響を限定したければ新しいO値を使う)。
- 表1:該当メイン商品のOを新しいO値に変更し、分類番号4(オプション)に「並、大盛り、特盛り」と「普通、多め、少なめ」を同一のO値で追加する。これにより、そのメイン商品を選択した際にそのO値に属するオプションだけが選べるようになる(「Oの値が一致するオプションだけが選択できる」のルールに合致)。
- 表2:上で追加したオプションに対応するイベントコードの列(例:403)を追加し、状態遷移表の必要な行(主に状態1でオプション選択を受け付け、選択後の状態を適切にするセル)に遷移先と値引き(通常は0)を設定する。もし「複数オプションを順に選べる」ようにしたければ、オプション列の該当状態セルを自己ループや次状態へ許可するよう設定すればよい(プログラムはstatus_tableの指定どおりに遷移・値引き・発券可を判断する)。
- 注意点(誤りやすいポイントへの対処):既存のO値(例えばO=1)に単に「つゆ量」を追加すると、O=1を持つ全てのメイン商品に影響してしまう。望まない副作用を避けるには、新しいO値を作り、対象のメイン商品のみOを変更することが必要である。
よって、イは表1(オプション追加・Oの割当変更)と表2(新イベント列の追加と遷移設定)だけで実現可能である。
ウ:サイドメニュー1とサイドメニュー2の商品で、セットメニューに組み込める商品を複数個ずつ注文したときに、値引きも複数回適用する。
- 表面上の考え方:表2の各セルには「遷移先の状態番号:値引きの金額」が入っており、判定プログラムはそれらを合算してdiscountを計算するので、値引き額を表2に書けば処理できそうに思える。だが実際には次の理由で表だけでは対応できない(あるいは現行要件との矛盾を生む)ことが多い。
- 主な理由:問題文に「値引きは食券購入ごとに1回だけ適用される」と明示されているため、現行の状態遷移図/状態遷移表は「1回適用」を前提に設計されている。複数回適用に変えるには、個々のセットを検出して都度50円を発生させるための「セット数のカウント」や「どの組合せが既に割引適用済みかの判定」といったロジックが必要になる。
- 理論的には表2を大幅に書き換えて状態を増やし、特定の並び/組合せごとに値引きセルを作れば限定的なケース(最大個数が固定)については実装できる可能性もあるが、実際の注文の順序や組合せは多様であり、任意数のセットに対して一般的に正しく割り当てるにはプログラム側で「数をカウントする」「組み合わせを判断する」処理を加える方が確実で保守的である。
- 結論:要求そのもの(「複数回適用」)は状態遷移表だけでは網羅的かつ安全に実現できないため、プログラム本体の変更(または運用上の別管理)が必要であり、表1, 表2のみでは対応不可と判断する。
- したがって、表だけで対応可能なのは「イ(オプションを追加・グルーピングする)」「エ(新しいメイン商品を追加し、その商品のオプション群を用意する)」であり、答えは イ、エ となる。
誤りやすいポイント
-
オプションの追加だけで済むと考える誤り
単に分類番号4にオプション行を追加しても、そのオプションがどのメイン商品に対して表示・選択可能かはO値の一致で決まる。既存のO値を流用すると想定外の商品にオプションが出てしまう。影響を限定するには新しいO値を割り当て、該当メイン商品の表1のOを変更する必要がある。 -
表2(状態遷移表)を忘れてしまう誤り
新しいオプションを追加したら、そのイベントコード(N,S,Oによる3桁)に対応する列を表2に追加して、どの状態で受け付けるか、遷移先・値引きをどうするかを定義しなければならない。get_event_index() がそのコードを見つけられるように表2側を整える必要がある。 -
時間依存や動的切替を表だけで実現できると考える誤り
「業務運用中に表1,2を差し替える」運用は問題文で禁止されている(運用中の変更は行わないものとする)。時間帯でオン/オフするにはプログラム側の時刻判定や運用手順が必要。 -
値引きの回数制御を表だけで安直に変える誤り
表2の値引き金額を書き換えるだけで済むケースもあるが、「複数回適用」のように任意個の組合せを正しく検出して重複なく割引を与えるには、個数をカウントする等のプログラム的処理が必要になることが多い。
FAQ
Q: イのように「並、大盛り、特盛り」の後に「つゆ量」を追加する際、既存のO=1を使えば楽ではないですか?
A: 既存のO=1をそのまま使うと、O=1を割り当てている全てのメイン商品で「つゆ量」が選べるようになってしまいます。対象を限定したければ新しいO値を設定し、表1で対象のメイン商品のOをその新値に変更し、分類番号4に「並、大盛り、特盛り」「普通、多め、少なめ」をそのOに属する行として追加します。さらに表2に新しいイベントコード列(例:403)を追加して遷移を定義する必要があります。
A: 既存のO=1をそのまま使うと、O=1を割り当てている全てのメイン商品で「つゆ量」が選べるようになってしまいます。対象を限定したければ新しいO値を設定し、表1で対象のメイン商品のOをその新値に変更し、分類番号4に「並、大盛り、特盛り」「普通、多め、少なめ」をそのOに属する行として追加します。さらに表2に新しいイベントコード列(例:403)を追加して遷移を定義する必要があります。
Q: エで「カレーには並、大盛りを指定できるが、特盛りは指定できない」を実現するにはどうすればよいですか?
A: カレーを表1に追加し、カレーのOを特盛りを含まない専用のO値に設定します(既存の特盛りが属するOを使わない)。分類番号4にその専用Oに属する「並」「大盛り」だけを追加(特盛りは追加しない)し、表2に対応するイベント列を追加して必要な遷移を設定します。こうすれば特盛りは選択の候補に現れません。
A: カレーを表1に追加し、カレーのOを特盛りを含まない専用のO値に設定します(既存の特盛りが属するOを使わない)。分類番号4にその専用Oに属する「並」「大盛り」だけを追加(特盛りは追加しない)し、表2に対応するイベント列を追加して必要な遷移を設定します。こうすれば特盛りは選択の候補に現れません。
Q: ウ(複数回の値引き)を単純に表2の値引き欄を変更して対応できませんか?
A: 制限は二点あります。まず、問題文の要件に「値引きは食券購入ごとに1回だけ適用される」と書かれており、この仕様を変えること自体が要件変更になります。仮に要件を変えるとしても、任意回数のセットを正しく検出して重複なく割引を与えるには、注文内の組合せをカウント/割当するロジックが必要で、単純に表2の値を繰り返し置くことで安全かつ一般的に実現できるとは限りません。したがってプログラムの変更が現実的です。
A: 制限は二点あります。まず、問題文の要件に「値引きは食券購入ごとに1回だけ適用される」と書かれており、この仕様を変えること自体が要件変更になります。仮に要件を変えるとしても、任意回数のセットを正しく検出して重複なく割引を与えるには、注文内の組合せをカウント/割当するロジックが必要で、単純に表2の値を繰り返し置くことで安全かつ一般的に実現できるとは限りません。したがってプログラムの変更が現実的です。
関連キーワード: 状態遷移表、イベントコード、オプショングループ、発券可フラグ、値引き集計






