blogoid

blogのようなもの

木幅と線形時間アルゴリズム

今回は木幅(tree-width)の話を書いてみようと思います。

木幅とは、大雑把に言うとグラフがどれだけ木に近いかを表す値です(木に近いほど小さな値になります)。NP困難な問題でもグラフを木に限定すると多項式時間で解けたりする話は有名ですが、実は一部のNP困難な問題は、グラフの木幅が定数で上から抑えられるなら、なんと線形時間で解くことができます!

今回はそのようなNP困難問題の一つである最大独立集合問題を取り上げて、木幅が定数で抑えられるときの線形時間アルゴリズムを紹介することを目標に記事を書いていこうと思います。

1. 木分解と木幅

 木幅を定義する前に、まずは木分解(tree-decomposition)を定義します。木分解とは、グラフを木構造として表現したものです。ちなみにグラフは無向グラフのみを考えます。

定義(木分解)

 グラフG=(V,E)G=(V,E)に対して、頂点集合VVの部分集合族X={X1,X2,...,Xk}X=\{X_1, X_2, ..., X_k\}X1,X2,...,XkX_1, X_2, ..., X_kを節点として持つ木TTの組(X,T)(X,T)であって、以下を満たすものをGGの木分解という。

  1. Xi(i=1,2,...,k)X_i(i=1, 2, ..., k)の和集合はVV
  2. GGにおいて辺で結ばれている任意の2点(u,v)(u,v)に対して、uuvvを両方とも含むXiX_iが存在する
  3. GGの任意の頂点vVv\in Vに対して、vvを含むXiX_i全体はTT上で連結

 

 イメージとしては、GGの各頂点vvに、vvを含むXiX_i全体がなすTTの部分木が対応しています。GGで頂点uuvvの間に辺があるなら、uuに対応するTTの部分木とvvに対応するTTの部分木が交わりを持つ(つまりuuvvを両方含むTTの節点XiX_iが存在する)という構造になっています。

例を見てみます。

f:id:mizuwater0:20181230174326p:plain

左が元のグラフ、右が左のグラフの木分解です。先ほどの木分解の定義の1~3を満たしていることが確認できます。

木分解が定義できたので、今度は木分解の幅と、グラフの木幅を定義します。

定義(幅、木幅)

 グラフGGのある木分解(X,T)(X,T)の幅とは、maxXiXXi1\max_{X_i\in X}|X_i|-1のことである*1。また、グラフGGの木幅tw(G)(G)とは、GGの全ての木分解の幅のうちの最小値である。

 

例えば、上の例における木分解の幅は2です。また、上の例におけるグラフは実は木幅も2です(つまり上に描いた木分解は幅が最小の木分解です)。

一般のグラフの木幅をすぐに求めるのは難しいですが、グラフクラスを限定すると木幅がすぐにわかったりします。例えば木の木幅は1であり(逆に連結なグラフで木幅が1なら木です)、また外平面的グラフ*2の木幅は2以下です。これを聞くと、確かに木幅が小さいほど木に近いグラフであるような気分になりますね*3

さて、実は与えられたグラフの幅最小の木分解を求めるのはNP困難問題です。ですが、木幅が定数で上から抑えられるなら、以下のBodlaenderの定理を用いて(V|V|に関する)線形時間で幅最小の木分解を求めることができます。

定理(Bodlaender 1996)

各定数ttに対して、以下を(ttを定数と見たときに)O(V)O(|V|)時間で行える。

入力として与えられたグラフG=(V,E)G=(V,E)に対して、その木幅がtt以下であるか否かを判定し、もしtt以下なら幅tt以下の木分解を構成する。

 

 与えられたグラフGGの木幅が定数llで上から抑えられるとします。このとき、Bodlaenderの定理をt=1,2,...,lt=1,2,...,lについて順番にGGに適用するか二部探索すれば、幅最小の木分解を(llを定数とみると)合計O(V)O(|V|)時間で得ることができます。これで幅最小の木分解を求める線形時間アルゴリズムが得られました。

(木幅が定数で抑えられるグラフに対する)最大独立集合問題の線形時間アルゴリズムも、この幅最小の木分解を求める線形時間アルゴリズムを使っています。このことは次の章以降で紹介していきます。

 2. Nice Tree-decomposition

 さて、グラフの幅最小の木分解が得られたとします。この木分解上でDPをまわすことで最大独立集合が求められるのですが、そのままDPをすると割と面倒です。そこでnice tree-decomposition と呼ばれるDPがしやすい木分解にあらかじめ変形しておいて、その木分解上でDPをまわす、ということがよく行われます*4。というわけで、この章では木分解上のDPを紹介する前にnice tree-decompositionを紹介しようと思います。

nice tree-decompositionとは、DPがしやすいように単純な構造しか持たないようにした木分解です。

定義(Nice Tree-decomposition)

nice tree-decompositionとは、木分解(X,T)(X,T)で、TTをある節点を根とした根付き木とみたときに以下を満たすもの*5

  1. 全てのXiXX_i\in Xは高々2つの子しか持たない
  2. XiX_iが2つの子XjX_jXkX_kを持つなら、Xi=Xj=XkX_i=X_j=X_kが成り立つ
  3. XiX_iが1つの子XjX_jを持つなら、GGのある頂点vVv\in Vが存在してXi=Xj{v}X_i=X_j\cup \{v\}またはXi=Xj{v}X_i=X_j\setminus \{v\}が成り立つ

 

2.を満たすXiX_iのことをjoin、3.を満たすXiX_iのうちXi=Xj{v}X_i=X_j\cup \{v\}を満たすものをintroduce、Xi=Xj{v}X_i=X_j\setminus \{v\}を満たすものをforgetと呼びます。 

例えば、木分解の定義の後で例に挙げたグラフのnice tree-decompositionは以下のようになります(一意ではありません)。

 

f:id:mizuwater0:20190102173730p:plain

 さて、(木幅が定数で抑えられるグラフに対して)幅最小の木分解がO(V)O(|V|)時間で得られることは前の章で説明しましたが、実はある木分解(X,T)(X,T)から同じ幅のnice tree-decompositionを得ることも(幅を定数として)O(X)O(|X|)時間で可能です。

補題

グラフGGの木分解(X,T)(X,T)に対して、同じ幅のnice tree-decompositionを(幅を定数として)O(X)O(|X|)時間で得ることができる。

証明)

与えられた木分解を(X,T)(X,T)とする。まず、TTの適当な節点XrXX_r\in Xを根と定めて、TTを根付き木として見る。次に、以下の3ステップの操作によりTTを変形することで、同じ幅のnice tree-decompositionを構成する。

  1.  3つ以上子を持つ節点の子を2つに減らす
  2. 節点XiX_iが2つの子XjX_jXkX_kを持ち、Xi=Xj=XkX_i=X_j=X_kが成り立たない場合、XiX_iの子を変える
  3. 節点XiX_iが1つの子XjX_jを持ち、「GGのある頂点vVv\in Vが存在してXi=Xj{v}X_i=X_j\cup \{v\}またはXi=Xj{v}X_i=X_j\setminus \{v\}が成り立つ」という関係が成り立たないとき、XiX_iXjX_jの間に節点を追加する
 各ステップの操作を詳しく見ていく。
まず、ステップ1.について、ある節点XiX_iが3つ以上子を持っていたとする。XiX_iの親をXjX_jとする。このとき、XiX_iのコピーを新たにつくり、XjX_jXiX_iの間に挿入する。また、XiX_iの子のうち、適当に1つ選んで親をXiX_iのコピーに変更する(下図参照)。
 

f:id:mizuwater0:20190103144052p:plain

この変形は木分解の条件を保ち、また木分解の幅も変化しない。また、コピーのほうのXiX_iの子は2つであり、コピーでないほうのXiX_iの子はもともとの個数よりも1つ少なくなっている。つまり、XiX_iに対してこれと同じ変形をまた施し、これを(子が3つ以上の)すべての節点について帰納的に繰り返せば、有限回の変形によってすべての節点の子を2つ以下にすることができる。これによって増える節点の個数はTTの辺の数以下なので、ステップ1.が終わった後の節点数はO(X)O(|X|)のままである。またステップ1.全体にかかる時間計算量は、幅を定数とみればO(X)O(|X|)時間である。ステップ1.が完了すると、nice tree-decompositionの定義の1つ目の条件が満たされていることになる。

次にステップ2.について、節点XiX_iが2つの子XjX_jXkX_kを持ち、Xi=Xj=XkX_i=X_j=X_kが成り立たないとする。このとき、新たにXiX_iのコピーを2つ作り、XiX_iXjX_jXiX_iXkX_kの間にそれぞれ挿入する(下図参照)。

f:id:mizuwater0:20190105161540p:plain

 この変形は木分解の条件を保ち、また木分解の幅も変化しない。この変形をステップ2.の条件に当てはまるすべての節点に対して行えば、nice tree-decompositionの定義の2つ目の条件が満たされることになる。ステップ2.全体で増える節点数、かかる時間計算量は幅を定数とみればともにO(X)O(|X|)である。

次にステップ3.について、節点XiX_iが1つの子XjX_jを持ち、「GGのある頂点vVv\in Vが存在してXi=Xj{v}X_i=X_j\cup \{v\}またはXi=Xj{v}X_i=X_j\setminus \{v\}が成り立つ」という関係が成り立たないとする。XiXj={u1,u2,...,up}X_i\setminus X_j=\{u_1,u_2,...,u_p\}とする。このとき、まずXiX_iXjX_jの間にXi{u1}X_i\setminus \{u_1\}を挿入する。次にXi{u1}X_i\setminus \{u_1\}XjX_jの間にXi{u1,u2}X_i\setminus \{u_1,u_2\}を挿入する。次にXi{u1,u2}X_i\setminus \{u_1,u_2\}XjX_jの間にXi{u1,u2,u3}X_i\setminus \{u_1,u_2,u_3\}を挿入する...と繰り返し、最終的にXi{u1,u2,...,up1}X_i\setminus\{u_1,u_2,...,u_{p-1}\}XjX_jの間にXi{u1,u2,...,up}X_i \setminus \{u_1,u_2,...,u_p\}を挿入する。ちなみにXi{u1,u2,...,up}=XiXjX_i \setminus \{u_1,u_2,...,u_p\}=X_i\cap X_jである。

XjXi={v1,v2,...,vq}X_j\setminus X_i=\{v_1,v_2,...,v_q\}についても同様の操作を行う。つまり、まずXiXjX_i\cap X_jXjX_jの間にXj{v1}X_j\setminus \{v_1\}を挿入する。次にXiXjX_i\cap X_jXj{v1}X_j\setminus \{v_1\}の間にXj{v1,v2}X_j\setminus \{v_1,v_2\}を挿入する...と繰り返し、最終的にXiXjX_i\cap X_jXj{v1,v2,...,vq2}X_j\setminus \{v_1,v_2,...,v_{q-2}\}の間にXj{v1,v2,...,vq1}X_j\setminus \{v_1,v_2,...,v_{q-1}\}を挿入する(Xj{v1,v2,...,vq}=XiXjX_j\setminus \{v_1,v_2,...,v_q\}=X_i\cap X_jに注意)。

例えばXi={1,2,3,4}X_i=\{1,2,3,4\}Xj={2,4,5,6,7}X_j=\{2,4,5,6,7\}の場合は下図のように節点が挿入される。

 

f:id:mizuwater0:20190103181913p:plain

この変形をステップ3.の条件に当てはまるすべての節点に対して行えば、nice tree-decompositionの3つ目の条件が満たされる。またこの変形は木分解の条件を保ち、幅も変化しない。また、集合XiX_iXjX_jの要素数は木分解の幅+1以下なので、1つの親と子の組(Xi,Xj)(X_i,X_j)に対してステップ3.の変形を行うことで増える節点数は、高々木分解の幅×2+1である。よって幅を定数とみれば、ステップ3.終了後の節点数はO(X)O(|X|)である。また、幅を定数とみればステップ3.全体でかかる時間計算量もO(X)O(|X|)である。

以上より、ステップ1、2、3によって、与えられた木分解(X,T)(X,T)から同じ幅で節点数O(X)O(|X|)のnice tree-decompositionがO(X)O(|X|)時間で得られることがわかる。\Box

3. Nice Tree-decomposition上のDP

 木幅が定数で抑えられるグラフG=(V,E)G=(V,E)が与えられたとします。すると、1章で述べた通り、幅最小の木分解(X,T)(X,T)O(V)O(|V|)時間で得ることができます。また、2章の補題より(X,T)(X,T)と同じ幅のnice tree-decompositionをO(X)O(|X|)時間で得ることができます。ここで、X=O(V)|X|=O(|V|)なので、これらを合わせることで合計O(V)O(|V|)時間で節点数O(V)O(|V|)で幅最小のnice tree-decompositionを得ることができます。

さて、幅最小のnice tree-decompositionが線形時間で得られることがわかったので、以下ではいよいよnice tree-decomposition上のDPによって最大独立集合問題が解けることを紹介していきます。

まず、最大独立集合問題に限らず木分解上でのDPは、次のように行われます。

  •  木分解(X,T)(X,T)に対して、適当な節点XrXX_r\in Xを選んでTTの根と定める*6
  • TTの各節点XiXX_i\in Xに対して、グラフGiG_iを、XiX_iとその子孫全体の和集合を頂点集合としてもつGGの誘導部分グラフ*7と定める
  • GGについて解きたい問題を、各GiG_iについて解くことで最終的に(Gr=GG_r=Gなので)GGについても解く
  • XiX_iが子Xi1,Xi2,...,XipX_{i_1}, X_{i_2}, ..., X_{i_p}を持っていたとき、GiG_iについて解きたい問題をGi1,Gi2,...,GipG_{i_1}, G_{i_2}, ..., G_{i_p}について解いた結果を用いて解く

上のDPについて、少し疑問を抱く方もいるかもしれません。つまり、GiG_iについて解きたい問題を、Gi1,Gi2,...,GipG_{i_1}, G_{i_2}, ..., G_{i_p}について解いた結果を用いて簡単に解けるのでしょうか?

 GiG_iのある2つの子GikG_{i_k}GilG_{i_l}の両方に含まれる頂点uuが存在したとします。このとき、uuXiX_iにも必ず含まれます。なぜかというと、uuを含むTTの節点全体は連結なので、XikX_{i_k}またはその子孫と、XilX_{i_l}またはその子孫を結ぶ道上にあるXiX_iにもuuが含まれるからです。

また、GiG_iに含まれる辺は、Gi1,Gi2,...,GipG_{i_1}, G_{i_2}, ..., G_{i_p}に含まれる辺か、両端点がXiX_iに含まれる辺のどちらかです。なぜかというと、GiG_iのある辺の2端点をu,vu,vとすると、XiX_iまたはその子孫でuuを含むもの、vvを含むものが少なくとも1つずつあります。また、uuvvの間には辺があるので、TTu,vu,vを同時に含む節点を持ちます。ここで、TT上でuuを含む節点全体、vvを含む節点全体はそれぞれ連結なので、XiX_iまたはその子孫でu,vu,vを両方とも含むものが必ず存在します。つまり、辺(u,v)(u,v)Gi1,Gi2,...,GipG_{i_1}, G_{i_2}, ..., G_{i_p}のいずれかに含まれるか、端点u,vu,vXiX_iに含まれるかのどちらかが成り立ちます。

よって、GiG_iについての問題をGi1,Gi2,...,GipG_{i_1}, G_{i_2}, ..., G_{i_p}についての結果を用いて解く際に、頂点の重複や新しく追加される辺という意味で考慮しなくてはいけないのはXiX_iまわりだけなので、XiX_iのサイズが小さい(つまり木分解の幅が小さい)なら高速にDPをまわして解くことができます。これが木分解上のDPの強みです。

では、実際に最大独立集合問題に対するnice tree-decomposition上でのDPを見ていきましょう。

 最大独立集合問題に対するDP

 nice tree-decomposition(X,T)(X,T)が与えられたとする。TTの節点XiX_iとその部分集合SXiS\subseteq X_iに対して、A[i,S]A[i,S]GiG_iの独立集合IIのうちIXi=SI\cap X_i=Sを満たすものの最大サイズと定める。A[i,S]A[i,S]を次のように更新していく。なおXiX_iの子は1つの場合XjX_j、2つの場合XjX_jXkX_kと表すことにする。また、XiX_iがintrodece、forgetのときのXiX_iXjX_jの差となる頂点をvvとする。

XiX_iが葉の場合: A[i,S]={S(S)(otherwise)\begin{aligned}A[i,S]=\begin{cases}|S|&(\text{Sは独立集合})\\ -\infty&(\mathrm{otherwise}) \end{cases} \end{aligned}
 
XiX_iがjoinの場合: A[i,S]=A[j,S]+A[k,S]SA[i,S]=A[j,S]+A[k,S]-|S|
 
XiX_iがintroduceの場合: A[i,S]={A[j,S](vS)A[j,S{v}]+1(vS,vS{v})(otherwise)\begin{aligned}A[i,S]=\begin{cases}A[j,S]&(v\notin S)\\ A[j,S\setminus\{v\}]+1&(v\in S, v\text{と}S\setminus\{v\}\text{の頂点を結ぶ辺がない})\\ -\infty&(\mathrm{otherwise}) \end{cases} \end{aligned}
 
XiX_iがforgetの場合: A[i,S]=max{A[j,S],A[j,S{v}]}A[i,S]=\mathrm{max}\{A[j,S],A[j,S\cup \{v\}]\}

 

 

XiX_iが葉、forgetの場合の式については少し考えれば成り立つことがわかると思います。XiX_iがjoinの場合の式は、GjG_jのうちXiX_iに含まれない頂点と、GkG_kのうちXiX_iに含まれない頂点との間に辺がないことから成り立ちます。また、XiX_iがintroduceで、vSv\in Sの場合については、GiG_iのうちXiX_iに含まれない頂点とvvの間には辺がないことに注意すると、vvS{v}(Xi)S\setminus \{v\}(\subseteq X_i)との間に辺がなければ、vvIXj=S{v}I\cap X_j=S\setminus\{v\}を満たすGjG_jの独立集合IIとの間にも辺がないので、A[i,S]=A[j,S{v}]+1A[i,S]=A[j,S\setminus\{v\}]+1が成り立ちます。

与えられたnice tree-decomposition(X,T)(X,T)の幅が定数ttTTの節点数がO(V)O(|V|)だとします。すると、このDPの時間計算量は、定数時間で終わる更新をO(2t+1V)O(2^{t+1}|V|)回行うので、合計O(V)O(|V|)時間かかります。よって、(木幅が定数で抑えられるグラフに対して)幅最小のnice tree-decompositionが線形時間で得られることもあわせて、最大独立集合問題が線形時間で解けることが示されました。

4. おまけ

前の章で、木幅が定数で抑えられるグラフに対して最大独立集合問題が線形時間で解けることを示しました。実は、もっと一般的に次のような事実が成り立ちます。

定理(Courcelle 1990)

 木幅が定数で抑えられるグラフと単項二階論理式で表現できるグラフについての命題が与えられたとき、グラフが命題を満たすかどうかを線形時間で判定できる

 

 (グラフについての)単項二階論理式とは次の表現を組み合わせて記述できる論理式のことです。

  • 論理結合子,,,¬,=,\land, \lor, \to, \lnot, =, \neq
  • 頂点、辺に関する量化子,\forall, \exists
  • 述語adj(u,vu,v)(uuvvの間に辺があるなら1を、ないなら0を返す)
  • 述語inc(e,ve,v)(vveeの端点なら1を、そうでないなら0を返す)
  • 頂点集合、辺集合に関する量化子,\forall, \exists
  • 頂点集合、辺集合に関する,\in, \subseteq

例えば、グラフが二部グラフである、独立集合である、閉路がある、3彩色可能、などの命題は単項二階論理式で表現可能です。

Coucelleの定理については証明とかも追ってなくてあまりよく知らないので、そのうちちゃんと勉強したいなと思います。

 

*1:なぜ1を引いているのかというと、木の木幅を1にするためです。

*2:外平面的グラフとは、すべての頂点が外面に面していて、かつ辺は交差しないような平面埋め込みをもつグラフです。例えば木分解の例のところで登場したグラフは外平面的グラフです。

*3:ならない人もいるかもしれません。

*4:nice tree-decompositionに変形せずにそのままDPをする場合の解法はWikipediaに漸化式などが載っています。この漸化式も本質的にはnice tree-decompositionに変形してからDPする場合の漸化式と同じです。

*5:葉と根は必ず空集合という条件を定義に含む流儀などもありますが、今回はそれは採用しませんでした。

*6:nice tree-decompositionに変形した場合はすでに根が定まっています。

*7:GG'GGの誘導部分グラフであるとは、GG'GGの部分グラフであり、かつ両端点がどちらもGG'に含まれるようなGGの辺はすべてGG'にも含まれるグラフのことをいいます