無向グラフのEuler circuitが存在するための必要十分条件は、連結で全次数が偶数であることです。しかし、存在が分かることと、実際に大きなグラフで一筆書きを出力できることは別です。本章では証明を有限手順へ変え、各辺を定数回しか調べない算法にします。
さらに、矢印に沿って進む有向グラフへ理論を拡張します。有向Euler circuitを「文字列の重なり」を表すグラフへ適用すると、長さ $k$ のすべての語を、重複なく一つの巡回列へ詰め込めます。例えば
$$
00010111
$$
を円周上に書くと、連続する3文字として二進列
$$
000,001,010,101,011,111,110,100
$$
がちょうど一度ずつ現れます。八つの語を個別に探す問題が、八本の有向辺を一度ずつ通る問題へ変わるのです。
以下、無向グラフの各辺には固有の番号が付いているとします。平行辺があっても番号で区別できます。隣接リストには、各辺について「相手の頂点」と「辺番号」を記録します。
使用済みかどうかを各辺に記録し、現在の頂点に接続する未使用辺を一本選んで進み、その辺を使用済みにする操作を繰り返す。この操作で得る辺列を未使用辺による小道|未使用辺によるtrailという。
同じ辺は使用済みにした後には選ばれないので、得られるwalkは確かにtrailです。その証明を、次の算法として書き直せます。
入力:辺をもつ頂点が一つの連結成分に属し、全頂点の次数が偶数である有限無向グラフ $G$。
ここには三つの疑問があります。途中で始点以外に行き止まらないか。未使用辺が残ったとき、本当に $C$ 上から再開できるか。貼り合わせを繰り返せば、有限時間で全辺を使うか。順に証明します。
全次数が偶数である無向グラフからclosed trailの辺をすべて除くと、残った各頂点の次数も偶数である。
closed trailが頂点 $v$ を通るたび、一本の辺で入り、別の一本で出ます。始点でも、最後に入る辺と最初に出る辺が対になります。従ってtrailが $v$ に接続して使う辺数は偶数です。元の偶数次数から偶数本を引くので、残余次数も偶数です。□
辺をもつ頂点が一つの連結成分に属するグラフで、closed trail $C$ が少なくとも一本の辺を使っているとする。未使用辺が残るなら、$C$ 上のある頂点に未使用辺が接続する。
未使用辺 $xy$ を一本取ります。$C$ 上の頂点 $c$ から $x$ へのpath
$$
c=v_0,v_1,\ldots,v_r=x
$$
があります。$x$ が既に $C$ 上なら、$xy$ が求める辺です。そうでない場合、path上で $C$ の頂点から $C$ 外へ初めて出る辺を $v_iv_{i+1}$ とします。
もしこの辺が使用済みなら、それは $C$ の辺ですから両端 $v_i,v_{i+1}$ が $C$ 上に現れるはずで、$v_{i+1}$ が $C$ 外であることに反します。従って $v_iv_{i+1}$ は未使用で、$C$ 上の $v_i$ に接続します。□
算法 [25-alg-hierholzer-splice] は有限回で停止し、入力グラフのEuler circuitを出力する。
最初に $s$ から延長不能になるまで未使用辺をたどります。全次数は偶数なので、偶数次数グラフのmaximal trailの議論により、このtrailは $s$ へ戻ります。
一つのclosed trailを取り除いた後の残余次数は補題 [25-lem-residual-even-degree] により偶数です。従って、手順3で選んだ $v$ から残余グラフ内を延長不能になるまで進むtrailも $v$ へ戻り、closed trail $D$ になります。
貼り合わせ補題により、辺を共有しない $C,D$ を $v$ で挿入したものは、両方の辺を一度ずつ使うclosed trailです。未使用辺が残れば、補題 [25-lem-unused-edge-meets-current-trail] により次の再開点があります。
各反復で少なくとも一本の未使用辺を使用済みにします。辺数 $m=|E(G)|$ は有限なので、反復は高々 $m$ 回で止まります。停止条件は未使用辺がないことですから、最後のclosed trailは全辺をちょうど一度ずつ使うEuler circuitです。□
closed trailを配列の途中へ何度も挿入すると、実装によっては要素の移動に時間がかかります。そこで、歩いている途中の頂点をstackに積み、行き止まりになった頂点から逆順に出力します。
入力:前節と同じグラフ $G$ と開始頂点 $s$。
S := [s]
L := 空列
while S が空でない:
v := S の末尾
if v に未使用辺 e=vw がある:
e を使用済みにする
w を S の末尾へ加える
else:
v を S から取り除き、L の末尾へ加える
L を逆順にして出力する
stack $S$ は、まだ最終出力へ確定していないtrailを表します。行ける辺があれば延長し、行けなくなった頂点は出力列の後ろ側から確定します。
算法の終了時、$L$ を逆順にした頂点列の隣り合う二頂点は、算法が使用済みにした相異なる辺で結ばれる。各使用済み辺はちょうど一度だけこの対応に現れる。
stack内では同じ頂点が何度も現れ得るので、頂点名ではなく出現位置を区別します。最初の $s$ 以外の各出現位置には、それをpushした固有の辺を「入辺」として対応させます。pushと使用辺は一対一なので、入辺は相異なります。
まず、算法が初めてpopを行うまでを見ます。それまでのpush列は、未使用辺を延長不能になるまでたどったtrailです。偶数次数の議論により、その終点は開始頂点 $s$ です。従ってstackには一つのclosed trailの頂点列が積まれています。
ここからpopを続けると、このclosed trailは逆順に $L$ へ移ります。途中の出現位置 $v$ で未使用辺が見つかれば、popはそこで止まり、$v$ から新たなpush列が始まります。残余次数は補題 [25-lem-residual-even-degree] により偶数なので、この新しいpush列も $v$ へ戻るclosed trailになります。そのtrailの頂点列が先に逆順で $L$ へ移り、その後に元のclosed trailのpopが再開します。従って、$L$ を逆順にした列では、新しいclosed trailが元の列の $v$ の位置へ挿入されています。
未使用辺がある限り同じことを繰り返すので、stack版が作る逆順列は、貼り合わせ版で相異なる辺からなるclosed trailを順次挿入した列と一致します。各挿入の前後で隣接頂点は対応するtrailの辺で結ばれ、同じ使用辺を二度挿入しません。また各push辺は、それを含むclosed trailの隣接箇所として必ず一度現れます。従って主張が成り立ちます。□
隣接リストを使い、各頂点について「次に調べる隣接項目」の位置を保存すれば、stack版Hierholzer算法はEuler circuitを $O(|V|+|E|)$ 時間、$O(|V|+|E|)$ 空間で出力する。
補題 [25-lem-stack-edge-correspondence] により、逆順の $L$ は、stack版が使用した辺をそれぞれ一度ずつ並べるclosed trailです。もし算法終了時に未使用辺が残っていれば、このclosed trail上の頂点に未使用辺が接続することが補題 [25-lem-unused-edge-meets-current-trail] から従います。しかしその頂点の最後の出現位置をpopするときには、接続する未使用辺があるため else へ進めず、先にその辺を使ってpushしなければなりません。これは未使用のまま終了したことに反します。従って全辺が使用され、出力はEuler circuitです。
計算量を数えます。無向辺は隣接リストに両端から一回ずつ、合計 $2|E|$ 個の項目として現れます。各頂点の走査位置は後ろへしか進まないため、全隣接項目を調べる回数は $O(|E|)$ です。各辺は一度だけ使用済みにされ、そのときpushが一回起こります。各pushされた頂点は一度だけpopされます。孤立頂点を含む入力表の準備に $O(|V|)$、隣接項目とstack・出力列に $O(|V|+|E|)$ 空間を使います。従って主張の計算量になります。□
Euler trailが閉じない場合も、算法を作り直す必要はありません。
連結な無向グラフ $G$ の奇数次数頂点が $s,t$ の二つだけなら、補助辺 $st$ を一本加えてHierholzer算法を実行し、得たEuler circuitを補助辺の位置で切れば、$s$ から $t$ へのEuler trailを得る。
補助辺を加えると $s,t$ の次数は偶数になり、他の次数は変わりません。従って増補グラフはEuler circuit $C$ をもちます。$C$ を補助辺 $t\to s$ の直後から書けば
$$
s,\ldots,t,s
$$
となります。最後の補助辺を削れば、元の全辺を一度ずつ使う $s$ から $t$ へのtrailが残ります。□
文字列の重なりでは「前半から後半へ」という向きが必要です。そこで辺を矢印にします。
向きを忘れ、各arcをその両端を結ぶ無向辺と見たグラフを基礎無向グラフと呼びます。孤立頂点はEuler問題に影響しません。
$d^+(v)=d^-(v)$ が全頂点で成り立ち、正次数頂点が基礎無向グラフで一つの連結成分に属する有向グラフでは、正次数頂点の任意の二頂点間に有向pathが両向きに存在する。
強連結成分を一頂点へ縮めて得る縮約有向グラフ $Q$ を考えます。異なる強連結成分間のarcだけを残せば、$Q$ は有向cycleをもちません。実際、成分間に有向cycleがあれば、そのcycle上の成分同士は相互に到達でき、一つの強連結成分でなければなりません。
$Q$ が二頂点以上なら、有限acyclic digraphなので入次数0の頂点、すなわち外部からarcが入らない強連結成分 $S$ があります。元の有向グラフで $S$ の頂点について
$$
\sum_{v\in S}\bigl(d^+(v)-d^-(v)\bigr)=0
$$
です。$S$ 内部の各arcは和へ $+1$ と $-1$ を一つずつ寄与して相殺します。残る値は「$S$ から外へ出るarc数」から「外から $S$ へ入るarc数」を引いたものです。後者は0なので、前者も0です。
従って $S$ と他の成分を結ぶarcはありません。しかし基礎無向グラフは正次数頂点上で連結なので、これは矛盾です。ゆえに強連結成分は一つだけです。□
一つ以上のarcをもつ有限有向グラフ $D$ が有向Euler circuitをもつための必要十分条件は、次の二条件である。
必要性を示します。有向Euler circuit上では、頂点 $v$ へ入るたびに次のarcで出ます。始点でも最後の入arcと最初の出arcが対になるため、全arcを数えると $d^+(v)=d^-(v)$ です。また、arcをもつ任意の頂点はcircuit上に現れるので、向きを忘れれば同じ連結成分に属します。
十分性を示します。正次数頂点 $s$ から未使用arcを向きに従って、延長不能になるまでたどります。終点を $t$ とします。もし $t\ne s$ なら、使用したtrailでは $t$ へ入った本数が $t$ から出た本数より1多いです。一方、全体では $d^-(t)=d^+(t)$ なので、未使用出arc数は未使用入arc数より1多く、特に未使用出arcがあります。これは延長不能に反します。従ってtrailは $s$ へ戻ります。
このclosed trailのarcを除くと、各頂点で除いた入arc数と出arc数が等しいため、残余有向グラフもbalanceしています。未使用arcが残るなら、基礎無向グラフの連結性を用いた補題 [25-lem-unused-edge-meets-current-trail] と同じpathの議論により、現在のclosed trail上の頂点 $v$ に未使用arcが接続します。そのarcが $v$ から出るなら直ちに再開できます。そのarcが $v$ へ入るものなら、残余で $d^+(v)=d^-(v)$ なので未使用出arcも少なくとも一本あります。
$v$ から同じ操作を行えば新しい有向closed trailが得られ、元のtrailへ挿入できます。各反復で使用arcが増えるので有限回で全arcを使い切ります。従って有向Euler circuitを得ます。□
補題 [25-lem-balanced-weak-strong] により、条件2を「正次数頂点上で強連結」と言い換えても同値です。ただし判定では、向きを忘れた連結性と次数balanceを別々に調べる方が簡単です。
有限有向グラフ $D$ が相異なる始点 $s$、終点 $t$ をもつ有向Euler trailをもつための必要十分条件は、正次数頂点が基礎無向グラフで一成分に属し、
$$
d^+(s)=d^-(s)+1,\qquad
d^-(t)=d^+(t)+1
$$
であり、$s,t$ 以外では $d^+(v)=d^-(v)$ となることである。
必要性は、trailの中間頂点では入るarcと出るarcが対になり、始点では出るarcが一本、終点では入るarcが一本余ることから従います。全arcが同じtrail上にあるため、弱連結性も必要です。
逆に条件が成り立つとします。補助arc $(t,s)$ を一本加えると、$s$ の入次数と $t$ の出次数がそれぞれ1増え、全頂点で入次数と出次数が等しくなります。弱連結性は保たれるので、前定理により増補グラフは有向Euler circuitをもちます。そのcircuitを補助arcの直後で切り、補助arcを削れば、$s$ から $t$ への有向Euler trailになります。□
アルファベット $A$ を有限集合とし、$|A|=q$ とします。$A^k$ は長さ $k$ の語全体です。
$k\ge2$ に対し、有向de Bruijnグラフ|de Bruijn graph $B(q,k-1)$ を次で定める。
例えば $A=\{0,1\}$、$k=3$ なら頂点は
$$
00,01,10,11
$$
です。語 $011$ はprefix $01$ からsuffix $11$ へのarc、語 $101$ は $10$ から $01$ へのarcになります。語 $000$ と $111$ はloopを与えます。
$B(q,k-1)$ は $q^{k-1}$ 頂点と $q^k$ arcをもち、各頂点の入次数・出次数はともに $q$ である。さらに正次数頂点上で強連結である。
長さ $k-1$ の語の各位置には $q$ 通りの選択があるので頂点数は $q^{k-1}$、長さ $k$ の語の個数は $q^k$ なのでarc数は $q^k$ です。
頂点 $u=a_1\cdots a_{k-1}$ から出るarcは、末尾に任意の文字 $b\in A$ を加えた語 $a_1\cdots a_{k-1}b$ に対応するので $q$ 本です。入るarcは、先頭に任意の $b\in A$ を加えた語 $ba_1\cdots a_{k-1}$ に対応するので、やはり $q$ 本です。
任意の二頂点
$$
u=a_1\cdots a_{k-1},\qquad v=b_1\cdots b_{k-1}
$$
を取ります。$u$ から順に $b_1,b_2,\ldots,b_{k-1}$ を末尾へ付け加えるarcをたどると、左端の文字が一つずつ落ち、$k-1$ 歩後に $v$ へ到達します。従って任意の $u$ から任意の $v$ への有向pathがあり、強連結です。□
位数 $k$、$q$ 文字のde Bruijn列とは、巡回的に並べた長さ $q^k$ の文字列で、巡回的に連続する長さ $k$ の部分語として $A^k$ の各語がちょうど一度ずつ現れるものをいう。
巡回的とは、末尾の次に先頭が続くという意味です。直線上に表示するときは、最初の $k-1$ 文字を末尾へ再掲すれば、長さ $q^k+k-1$ の表示になります。
任意の整数 $q\ge1$、$k\ge1$ に対し、位数 $k$、$q$ 文字のde Bruijn列が存在する。
$k=1$ なら、$q$ 個の文字を一度ずつ円周上に並べればよいです。以下 $k\ge2$ とします。
補題 [25-lem-de-bruijn-balanced-connected] により、$B(q,k-1)$ は全頂点で入次数と出次数が等しく、正次数頂点上で連結です。有向Euler circuitの定理から、$q^k$ 本のarcを一度ずつ通るcircuitがあります。
circuitの開始頂点を
$$
a_1a_2\cdots a_{k-1}
$$
とし、順に通るarcの終点へ新たに入った末尾文字を
$$
c_1,c_2,\ldots,c_{q^k}
$$
とします。直線上では
$$
a_1a_2\cdots a_{k-1}c_1c_2\cdots c_{q^k}
$$
と書けます。
$i$ 番目のarcを通る直前の頂点は、その時点の末尾 $k-1$ 文字であり、そこへ $c_i$ を付けた長さ $k$ の語が、そのarcのlabelです。Euler circuitは各arcをちょうど一度通り、arcは $A^k$ の語と一対一に対応します。従って連続する長さ $k$ の窓には、各語がちょうど一度ずつ現れます。
circuitは開始頂点へ戻るので、最後の $k-1$ 文字は最初の $a_1\cdots a_{k-1}$ と一致します。この重複部分を除き、円周上に $q^k$ 文字を置けばde Bruijn列になります。□
$B(2,2)$ のarcを語で書くと
$$
000,001,010,011,100,101,110,111
$$
です。例えば次の有向Euler circuitを取れます。
$$
00\xrightarrow{000}00
\xrightarrow{001}01
\xrightarrow{010}10
\xrightarrow{101}01
\xrightarrow{011}11
\xrightarrow{111}11
\xrightarrow{110}10
\xrightarrow{100}00.
$$
開始頂点 $00$ の後へ、各arcで新たに加わる文字
$$
0,1,0,1,1,1,0,0
$$
を並べると、直線表示は
$$
0001011100
$$
です。末尾の $00$ は巡回の重複なので、円周上では
$$
00010111
$$
を得ます。
長さ3の窓を一文字ずつずらすと
$$
000,001,010,101,011,111,110,100
$$
となり、確かに全8語が一度ずつです。最後の二窓 $110,100$ は、列の末尾から先頭へ回り込んでいます。
長さ $k$ の語を頂点にして、重なり合う語同士を結ぶ方法も考えられます。その場合、「各語を一度ずつ現す」はHamilton cycleを探す問題になります。しかしHamilton cycleの一般的な存在判定は、次数だけでは決まりません。
de Bruijn graphでは、求めたい長さ $k$ の語を辺にし、重なり部分の長さ $k-1$ の語を頂点にしました。すると各語を一度ずつ使う条件がEuler問題になり、入次数と出次数のbalanceだけで存在を保証できます。対象を頂点に置くか辺に置くかというmodel化の選択が、難しい問題を構成可能な問題へ変えています。
同じ考えは、DNA断片の重なり、短い文字列をすべて含む試験系列、カードやタイルの接続条件にも現れます。ただし現実のDNA assemblyでは誤り・反復・不完全な観測があるため、完全なEuler circuitだけでは足りません。本章の模型は、その複雑な問題の理想化された出発点です。
辺集合
$$
\{12,23,31,14,45,51\}
$$
をもつグラフで、まずclosed trail $1,2,3,1$ を作ったとする。Hierholzer算法の残りを実行し、Euler circuitを構成せよ。
最初のtrailが使っていない辺は $14,45,51$ です。現在のtrail上の頂点1に未使用辺が接続するので、1から
$$
1,4,5,1
$$
というclosed trailを作れます。最初のtrailの最後の1の位置へ挿入すれば
$$
1,2,3,1,4,5,1
$$
です。六辺がすべて一度ずつ現れるのでEuler circuitです。□
頂点集合 $\{1,2,3,4\}$、辺集合
$$
\{12,23,34,41,13\}
$$
について、補助辺を用いて1から3へのEuler trailを構成せよ。
次数は1と3で3、2と4で2です。奇数次数頂点1,3の間に、元の辺13とは番号で区別した補助辺 $e_*$ を加えます。増補グラフのEuler circuitとして
$$
1,2,3,4,1,3,1
$$
を取れます。最後の $3,1$ を補助辺 $e_*$ と選び、そこを切ると
$$
1,2,3,4,1,3
$$
が残ります。これは元の五辺を一度ずつ使う1から3へのEuler trailです。□
頂点 $a,b,c,d$ とarc
$$
a\to b, b\to c, c\to a, a\to d, d\to c
$$
をもつ有向グラフについて、有向Euler circuitまたは有向Euler trailが存在するか判定し、存在するものを一つ書け。
次数は
$$
\begin{array}{c|cccc}
v&a&b&c&d\\ \hline
d^+(v)&2&1&1&1\\
d^-(v)&1&1&2&1
\end{array}
$$
です。$a$ では出次数が1多く、$c$ では入次数が1多く、他はbalanceしています。基礎無向グラフは連結なので、$a$ から $c$ への有向Euler trailがあります。例えば
$$
a\to b\to c\to a\to d\to c
$$
です。始終点が異なるのでEuler circuitはありません。□
$B(2,2)$ の全頂点・全arcを書き、本文とは異なる有向Euler circuitを一つ探して、位数3の二進de Bruijn列を作れ。
頂点は $00,01,10,11$、arcは長さ3の全二進語です。例えば
$$
00\xrightarrow{001}01
\xrightarrow{011}11
\xrightarrow{111}11
\xrightarrow{110}10
\xrightarrow{101}01
\xrightarrow{010}10
\xrightarrow{100}00
\xrightarrow{000}00
$$
は全arcを一度ずつ使います。開始頂点00と、順に付け加わる文字 $1,1,1,0,1,0,0,0$ を並べると
$$
0011101000
$$
です。末尾00を重複分として除くと、巡回列
$$
00111010
$$
を得ます。その巡回3文字窓は
$$
001,011,111,110,101,010,100,000
$$
で、全二進3語を一度ずつ含みます。□
$q\ge2$、$k\ge2$ とする。$B(q,k-1)$ では任意の頂点から任意の頂点へ高々 $k-1$ 本のarcで到達できることを示せ。また、相異なる文字 $0,1\in A$ に対し、頂点 $00\cdots0$ から $11\cdots1$ へは少なくとも $k-1$ 歩必要であることを示せ。
任意の目標頂点 $b_1\cdots b_{k-1}$ に対し、現在の頂点の末尾へ $b_1,b_2,\ldots,b_{k-1}$ を順に追加すれば、$k-1$ 歩後には目標頂点になります。従って距離は高々 $k-1$ です。
$00\cdots0$ から一歩進むと、元の0を左から一つ捨て、新しい文字を右へ一つ加えます。$r$ 歩後にも、$r< k-1$ なら元の0が少なくとも一つ残っています。従って全成分が1の頂点には到達できません。ゆえにこの二頂点間の距離は少なくとも $k-1$ で、実際にちょうど $k-1$ です。□
$q$ 文字の巡回列が、長さ $k$ の全 $q^k$ 語を少なくとも一度ずつ含むなら、巡回列の長さは少なくとも $q^k$ であることを示せ。de Bruijn列がこの下界を達成することを説明せよ。
長さ $N$ の巡回列には、開始位置を一つ指定するごとに長さ $k$ の巡回部分語が一つあり、開始位置は $N$ 箇所です。従って異なる長さ $k$ 語は高々 $N$ 個しか現れません。全 $q^k$ 語を含むには
$$
N\ge q^k
$$
が必要です。
de Bruijn列の長さは定義により $q^k$ で、その $q^k$ 個の窓がすべて異なる語です。従って下界を等号で達成し、可能な巡回列のうち最短です。□
無向Euler graphの存在証明を、$O(|V|+|E|)$ 時間で実行できるHierholzer算法へ変えました。有向グラフでは「入る本数と出る本数のbalance」と弱連結性がEuler circuitを特徴づけます。そして長さ $k$ の語をarc、長さ $k-1$ の重なりを頂点に置くことで、全語を一度ずつ含む最短巡回列をEuler circuitとして構成しました。
Mathpediaは寄付と、参考文献の書籍リンク(Amazonアソシエイト)の紹介料で運営されています。 支援について / 寄付する