応用情報技術者 2016年 春期 午前2 問05
問題文
A, B, Cの順序で入力されるデータがある。各データについてスタックへの挿入と取出しを1回ずつ行うことができる場合、データの出力順序は何通りあるか。

選択肢
ア:3
イ:4
ウ:5(正解)
エ:6
🔒 解説は解答すると表示されます
スタック出力順列【午前2解説】
正解の理由
入力順が A → B → C のとき、スタック(LIFO)操作で可能な出力順は 5 通りあります。具体的には次の順序が可能です:ABC、ACB、BAC、BCA、CBA。これらは各データを1回ずつ push(挿入)と pop(取出)で出力する過程で実現できます。したがって選択肢の中では ウ が正しいです。
特に注意すべきは「CAB」が含まれるかどうかで、これは不可能です。C を先に出力するためには A, B をスタックに残したまま C を push して pop する必要がありますが、その後スタックには下から A, 上に B の順で残っています。したがって A を B より先に出力することはできず、CAB は実現不能です。正しくは C を先に出して残りを出す順序は CBA(C → B → A)になります。
解法ステップ
- スタックの性質を確認(LIFO:後入れ先出し)。
- 入力 A, B, C を順に処理し、各要素は一度 push され一度 pop されるという制約を守る。
- 実際に可能な出力列を、push/pop の操作列として全探索または論理的に列挙する。
- 例:A を push してすぐ pop すれば先頭は A(→ ABC, ACB の候補)。
- B を先に出す場合は A を push したまま B を push → B を pop(→ BAC, BCA の候補)。
- すべてを push してから順に pop すれば CBA。
- 個数を数えると 5 通りになる。一般化すると、長さ n のときスタック出力順列の個数はカタラン数 。
選択肢別の誤答解説
- ア: 3
- 誤り。明らかに ABC、ACB、BAC の少なくとも 3 通りは可能だが、それ以外に BCA と CBA が追加で可能であるため 3 は不足。
- イ: 4
- 誤り。4 と考える受験者は「CAB が不可能なので 6-1 = 5 のところをもう一つ見落としている」場合が多い。実際はもう一通り(例えば BCA)を数え漏らしている。
- ウ: 5
- 正答。上で挙げた ABC、ACB、BAC、BCA、CBA の 5 通りがすべて実現可能であり、他の順序(特に CAB)は不可能であるためこれが正しい。
- エ: 6
- 誤り。全順列 6 通り(ABC, ACB, BAC, BCA, CAB, CBA)のうち CAB がスタック制約で実現できないため最大でも 5。
各出力順に対応する一例の操作列(push を +、pop を −、出力は右側)を示します。
- ABC: +A −A +B −B +C −C
- ACB: +A −A +B +C −C −B
- BAC: +A +B −B −A +C −C
- BCA: +A +B −B +C −C −A
- CBA: +A +B +C −C −B −A
(上記の操作は「各要素を1回ずつ挿入・取出しする」という条件を満たします)
よくある誤解
- 全順列が可能だと思う(6通り):キューと混同していたり、スタックの LIFO 制約を忘れて起こる誤りです。スタックでは入れた順序の逆順でしか取り出せない側面があります。
- CAB は可能だと誤認する:C を先に出した後に A を B より先に出せないというスタック構造を見落とすミスです。C を pop すると B が A の上にあるため A を先に pop できません。
- カタラン数を知らずに個別列挙を怠る:n が大きくなると手で列挙できないため、カタラン数などの一般公式を知らないと誤答につながります。
補足コラム
- 一般化:長さ n の入力列に対してスタックで可能な出力列の個数はカタラン数 です。今回の n=3 では になります。
- 判定法:ある順列がスタックで生成可能かを判定するには「スタックシミュレーション」を行えば確実です。別の数学的特徴として、スタック生成可能な順列は「231 を含まない」パターン(231-回避)として特徴付けられます。
補助的に、全通りをプログラムで列挙する簡単な例(Python):
def stack_perms(seq):
res = []
def dfs(inp, stack, out):
if not inp and not stack:
res.append(tuple(out))
return
# push if input available
if inp:
dfs(inp[1:], stack + [inp[0]], out)
# pop if stack not empty
if stack:
dfs(inp, stack[:-1], out + [stack[-1]])
dfs(list(seq), [], [])
return res
print(stack_perms("ABC")) # => [('A','B','C'), ('A','C','B'), ('B','A','C'), ('B','C','A'), ('C','B','A')]
FAQ
Q. なぜ CAB が不可能なのか、手短に教えてください。
A. C を先に出すためには A,B をスタックに入れたまま C を push→pop します。その時点でスタックの上には B があり、下に A があるため A を B より先に取り出すことはできません(A は B の下にある)。よって CAB は実現できません。
A. C を先に出すためには A,B をスタックに入れたまま C を push→pop します。その時点でスタックの上には B があり、下に A があるため A を B より先に取り出すことはできません(A は B の下にある)。よって CAB は実現できません。
Q. 他の長さの場合も同じ方法で数えるのですか?
A. 小さい n(例えば n≤5)なら列挙で可能ですが、一般にはカタラン数の公式 を使うと効率的です。
A. 小さい n(例えば n≤5)なら列挙で可能ですが、一般にはカタラン数の公式 を使うと効率的です。
関連キーワード: スタック、LIFO、カタラン数、スタック順列、順序制約、push/pop

\ せっかくなら /
応用情報技術者を
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

