次数の条件がついた なもり木 のより善い数え方
CODE FESTIVAL 2017 Elimination Tournament (名前が長い!) の F 問題 の想定解よりも善い解法です. atcoder.jp
問題概要
以下の条件を満たすような 頂点の無向グラフは何通りあるか.(頂点は区別する)
- グラフは単純で連結
- 頂点 の次数は
の総和が のとき(つまり,グラフが木のとき),答えは である.
では, の総和が のとき(つまり,グラフが俗に言う「なもり木」*1のとき) はどうか?
想定解は ですが,実は で解くことができます.
Prüfer Code
Prüfer Code は,各要素が のいずれかである長さ の数列です. 通りある Prüfer Code と 頂点のラベル付き無向木の間には,1対1対応が存在します.
木に対する Prüfer Code は,以下の操作を 回繰り返して得られる長さ の数列 です.
- 回目の操作とする.現在の葉のうち,最も番号の若いものを選ぶ(これを とおく).と唯一隣接している頂点の番号を とし, を木から取り除く.
次のように考えると,Prüfer Code から木を復元できることがわかります.
- 回目の操作における「現在の葉」がわかれば,そのうち最も番号の若いものが と判明します.
- ここで,以前の操作で取り除いた頂点たち,つまり は明らかに葉になりえません.また, は現在の内点*2であり,逆に現在の内点はここに現れます(図を描いて確かめてみよう).したがって, 以外の頂点が現在の葉です.
- 回目の操作で取り除かれた辺は 頂点 を結ぶものです.全操作を終えた後は 頂点の木になるはずなので, として登場しなかった 頂点間に最後まで残った 辺があります.
たとえば,以下のグラフに対応する Prüfer Code は です.
上の2つは互いに逆の操作になっています.あらゆる に対して「復元」によって木が作れるので,1対1対応があるとわかりました.
解法
Prüfer Code の考え方を応用します.
まずは木のときを確かめます.木の Prüfer Code において, の登場回数は に等しいことから,木のときの問題は以下のように言い換えられます.
長さ の数列であって, が 回現れるものは何通りか.
これは簡単に解けて,結果は問題概要にある通りになります.
これを参考に,なもり木における「Prüfer Code もどき」を以下のように定義します.
- を 個含む,長さ の数列.
- 「Prüfer Code もどき」からの なもり木 の復元は,以下のようにして行う.
- 残りの要素がuniqueでない間は,木のときと同様に「現在の葉」を求め,最も番号の若い葉と を辺でつなぐ操作を繰り返す.
- 残りの要素がuniqueになったら,残りの要素を円状に並べ,隣接する つの番号の頂点を辺でつなぐ.
たとえば, という「Prüfer Code もどき」からは,以下の なもり木 が復元されます.
わかりやすさのために,
- 閉路の長さが の なもり木のことを 「-なもり木」,
- 「Prüfer Code もどき」のうち
- 末尾 要素がuniqueなものを「-もどき」,
- uniqueな接尾辞の最大長が ,つまり "-もどき" だが "-もどき" ではないものを「ちょうど -もどき」
と呼ぶことにします.「ちょうど -もどき」は必ず「-なもり木」を復元することに気を付けてほしい.なもり木の閉路は必ず長さ 以上なので, として考えます.
数え上げに落とす
ある -なもり木 を復元する ちょうど -もどき は何通りか.
実は,末尾 要素以外は一意に定まります.これは直感的に明らかだし,実際に帰納法から導けます.末尾 要素は閉路を導く部分ですが,ここは任意の -なもり木 について 通りです(左回り・右回りで 通り,特定の要素を何番目に置くかで 通り).
したがって, -なもり木 の個数は,ちょうど -もどき の個数を で割った値に等しくなります.ちょうど -もどき の個数は -もどきの個数から -もどきの個数を引けば求まるので,全ての について -もどき の個数が求まれば解けます.
という挿入DPを定義すると,
という漸化式で解くことができます(なお,).
以上より,この問題を で解くことが出来ました.いゃっほー!
参考文献
*1:「なもり」という漫画家がおり,Twitterでのアイコンがグラフに似ていることから.
*2:葉でない頂点のこと.