基本情報技術者 2010年 秋期 午前(科目A) 問06
問題文
節点1, 2, …, nをもつ木を表現するために、大きさの整数型配列A[1], A[2], …, A[n]を用意して、節点iの親の番号をA[i]に格納する。節点iが根の場合はA[i]=0とする。表に示す配列が表す木の葉の数はいくつか。

選択肢
ア:1
イ:3
ウ:5(正解)
エ:7
🔒 解説は解答すると表示されます
親配列表現の葉数【午前解説】
正解の理由
与えられた親配列 A において、葉とは「他の節点の親として一度も現れない節点」です。配列 A の値の集合(ただし 0 は根の印なので除く)に含まれる節点は少なくとも1つ以上の子を持つ節点、すなわち内部節点です。よって葉の個数は全節点数 から「親として出現する節点の種類数」を引いた数になります。今回、 であり配列の親として現れる節点の集合は (0 は除く)で種類数は 3 です。したがって葉の個数は で、選択肢ウが正解です。
解法ステップ
- 親配列 A[1..n] を確認する(ここでは A = [0,1,1,3,3,5,5,5])。
- 配列の値のうち 0 を除いた異なる値(distinct values)を求める。これが「親として出現する節点の集合」である。
- 葉の個数は からその集合の要素数を引く:葉数 = 。
- 値を代入して計算する:。
数学的には、葉の個数を 、節点数を 、親として出現する節点の種類数を とすると
となります。
選択肢別の誤答解説
- ア: 1
1 を選ぶのは根だけを葉と誤認する場合に起こります。根は子を持たなければ葉になりますが、今回の根(節点1)は子(節点2,3)を持っているため葉ではありません。 - イ: 3
「子が1つの節点」を数えるなどの別の誤りが考えられます。今回、子を持つ節点は 1,3,5 の3つですが、これは内部節点の数であって葉の数ではありません(葉は内部節点以外の節点)。 - エ: 7
7 を選ぶのは「重複をカウントしない」「親として現れるかどうかではなく、子の総数を誤って数えた」などの計算ミスが原因です。親配列中に現れる値の重複(例えば 5 が3回現れる)は内部節点の種類数を増やすものではありません。重複は1つとして扱います。
よくある誤解
- 「親配列での登場回数を数えれば良い」と思い込み、異なる親ノードの種類ではなく出現回数の合計を用いるミス。重複は1回しか数えない(集合で見なす)点に注意してください。
- 0 を親集合に含めてしまうミス。0 は根の印なので葉判定のための親集合には含めません。
- 親として出現する節点の種類数の下限を常に 1 としてしまう誤解。一般には が成り立ちます(特に のときは少なくとも1つの親が存在するため )。
補足コラム
- 一般的なアルゴリズム実装は O(n) で行えます。親配列を1回走査して 0 を除く親番号を集合に入れ、その集合のサイズを用いて葉数を求めます。
- 親配列は根を指す要素に 0 を使う慣習がありますが、別の表現(-1 や self-indexing)を使う問題もあり得ます。符号や特別値に注意して同様の集合処理を行ってください。
例(Python、1-based を想定した簡単な実装):
A = [0,1,1,3,3,5,5,5] # 長さ n (=8)
parents = set(x for x in A if x != 0)
n = len(A)
leaves = n - len(parents)
print(leaves) # 5
FAQ
Q: 配列内に親番号が自分自身の値として書かれているときは?
A: 木の定義では自己ループは許されません。自己番号が親として現れる場合は、その節点が子を持つ(内部節点)と扱いますが、与えられた構造が「木」であることを前提に問題が作られているはずです。
A: 木の定義では自己ループは許されません。自己番号が親として現れる場合は、その節点が子を持つ(内部節点)と扱いますが、与えられた構造が「木」であることを前提に問題が作られているはずです。
Q: 複数の根(森)の場合はどうする?
A: 設問が「木」を対象としている限り根は1つですが、一般に森林(複数根)でも同様の考え方が使えます。各根は A[i]=0 となり、葉の個数は同様に で求まります。
A: 設問が「木」を対象としている限り根は1つですが、一般に森林(複数根)でも同様の考え方が使えます。各根は A[i]=0 となり、葉の個数は同様に で求まります。
関連キーワード: 親配列、葉の計算、木構造、集合操作、アルゴリズム設計

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

