応用情報技術者 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

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

