かんプリンの学習記録

勉強したことについてメモしています. 主に競技プログラミングの問題の解説やってます.

グリッドの最短経路の数え上げまとめ

グリッドの最短経路(North-East lattice path)の数え上げの例を解説していきます.よくある書き込み(動的計画法)による解法は扱いません.

最短経路の数え上げとは

最短経路の数え上げは,以下のようなグリッド上で左下から右上への最短経路(North-East lattice path)の数を数え上げる問題です.最短経路の例として以下の赤,青の経路があります.

一般的な最短経路

例として,以下の縦4区画,横6区画のグリッド上の最短経路を考えます.

どの最短経路でも上方向に4回,右方向に6回移動する必要があります.最短経路の数は「4つ,「6つを並べる方法の数に等しいです.例えば上の赤の経路は(,,,,,,,,,)に対応しています.これは同じものを含む順列の数え上げに等しく,(104)=210が答えとなります.ここで,(nr)とはn!r!(nr)!のことです.

ある点を通る最短経路

グリッド上の最短経路のうち,ある点Pを通るようなものの数は,(左下から点Pまでの最短経路の数)×(点Pから右上までの最短経路の数)となります.

例えば以下のグリッドの左下から右上への最短経路のうち,赤の点を通るよううなものの数は,(63)(41)=80です.

Pが辺上にあっても数え方は同じで,その辺の両端の点を通るような経路の数を数えればよいです.以下の例で赤の点を通るような物の数は,(52)(42)=60です.

ある点を通らない最短経路

全体の経路の数からある点を通る最短経路の数を引けばよい.

通ってはいけない点が複数ある場合

ある長方形領域を通らない最短経路

以下のようにグリッド上に左上から右下にかけてのオレンジの破線上の点を考えます.このグリッド上の左下から右上への最短経路は必ずオレンジの点を通ります.さらに,異なる2つのオレンジの点を通る最短経路は存在しないため,各オレンジの点を通る最短経路数の総和は,全体の最短経路数と一致します.

以下のようなグリッド上の長方形領域が通れないときの最短経路を数えます.先ほどのように直線を引き,その直線上の各点を通る最短経路数を足せばよいです.

また,このままでは上から2番目のオレンジの点は数えにくいので以下のように直線をずらしてみます.

「異なる2つのオレンジの点を通る最短経路は存在しない」,「各点を通る最短経路数の総和は,全体の最短経路数と一致する」を満たすため,このように変形しても問題ないです.

この場合の最短経路数は(44)(60)+(43)(61)+(51)(53)+(50)(54)=80となります.

一般に,長方形領域が通れない場合,その長方形の頂点から引いた直線を引くとこのように求めることができます.

ある直線を跨がない最短経路

傾き1の直線を跨がない最短経路(直線1本)

以下のようなグリッド上の直線を跨がない(直線上の点は通ってもよい)最短経路の数を数えます.

この直線を跨がないということは以下の灰色の直線上の点を通らないということになります.

このグリッドをこの通ってはいけない灰色の直線で折り返すと以下のようになります.数えたいものは黒点から赤点まで灰色の点を通らずに行く最短経路数です.これは「黒点から赤点までの最短経路数」から「黒点から赤点までで灰色の点を通るような最短経路数」を引けば良いです.ここで,「黒点から赤点までで灰色の点を通るような最短経路数」というのは「黒点から青点までの最短経路数」と等しいです.なぜならば,「黒点から青点までの最短経路」は必ず1度は灰色の点を通り,そのうち初めに通った灰色の点以降の経路を直線で折り返すと「黒点から赤点までで灰色の点を通るような最短経路」と1対1対応するからです.

例えば以下の赤の経路と青の経路が対応します.

この場合の最短経路数は(104)(102)=165となります.

一般に,縦N区画,横M区画のグリッドの上からK区画にかけて以下のように直線がある場合,その直線上の点を跨がない最短経路の数は,

(N+MN)(N+MK1)

となります.

特に,M=N,K=Nの場合,この値はカタラン数と呼ばれ,

CN=(2NN)(2NN1)=1N+1(2NN)

と表されます.

傾き1の直線を跨がない最短経路(直線2本)

下図のように複数の直線があっても複数回折り返すことで同じように解くことができます.

(黒赤)(黒青)(黒黄)+(黒緑)が答えとなります.ただし,直線の位置によっては多くの回数折り返す必要がある場合があります.

一般に,縦N区画,横M区画のグリッドの上からK区画,下からL区画にかけて以下のように直線がある場合,その直線を跨がない最短経路の数は,P=N+MKL+2として,

kZ(N+MN+kP)(N+MK1+kP)

となります.

傾き1の2本の直線の間を通る最短経路

stを整数として,直線y=x+sy=x+tの間を通る(直線上は通ってもよい)条件のもとで,格子点上を上か右のみの移動で(a,b)から(c,d)に移動する経路数は
kZ((c+dabcak(ts+2))(c+dabcbk(ts+2)+t+1))

となることが知られています.*1
傾き1の直線を通らない最短経路(直線2本)はこれの特殊な例となっています.

傾き1/μの直線を跨がない最短経路

μを正負整数として,直線y=1μxを跨がない(直線上は通ってもよい)条件のもとで,格子点上を上か右のみの移動で(a,b)から(c,d)に移動する経路数は

(c+dabca)i=a/μ+1d(i(μ+1)ab1ib)cμd+1c+di(μ+1)+1(c+di(μ+1)+1di)

もしくは
i=0a/μb(1)i(aμ(b+i)i)×cμd+1c+d(μ+1)(b+i)+1(c+d(μ+1)(b+i)+1dbi)

となることが知られています.*2

特に,(a,b)=(0,0)のとき,

cμd+1c+d+1(c+d+1d)

となります.

傾きq/pの直線を跨がない最短経路

p,qを互いに素な正整数として,直線y=qpxを跨がない(直線上は通ってもよい)条件のもとで,格子点上を上か右のみの移動で(0,0)から(p,q)に移動する経路数は

1p+q(p+qp)

となることが知られています.*3

p=n,q=n+1とすることで,カタラン数になることも確認できます.

また,この直線より上側にある「経路上の格子点」の数がK個(0K<p+q)であるような経路数も同様に

1p+q(p+qp)

となります(Kの値によらない).より一般的な場合も計算できますが,効率的な計算方法は分かっていないようです.*4

対角線上をK回通る最短経路

縦横N区画のグリッドの左下から右上への最短経路のうち,グリッドの対角線上の(始点と終点を除く)点ををちょうどK回通るものの数を数えます.例えば以下の最短経路は対角線上の点を3回通っています.

対角線上の点のうち通るものを決めると,点と点の間は「対角線上の(始点と終点を除く)点を通らない最短経路数を求めよ.」という複数の部分問題に分割できます.下図のうち,オレンジの点が通る点,青の枠が部分問題になっています.

「縦横t区画のグリッドの左下から右上への最短経路のうち,グリッドの対角線上の(始点と終点を除く)点を通らないものの数を求めよ.」という部分問題の解を求めます.これは簡単で,下図において,左下の赤(青)点から右上の赤(青)点まで対角線(オレンジ)を通らない最短経路の数を求めればよいです.ある直線を跨がない最短経路で紹介したカタラン数を用いて2Ct1と表すことができます.

あとは,サイズの和がNになるような部分問題の積の和を求めればよいです(畳み込み).

t1+t2++tK+1=N(2Ct11)(2Ct21)(2CtK+11)=2K+1t1+t2++tK+1=NCt11Ct21CtK+11

t1+t2++tK+1=NCt11Ct21CtK+11はカタラン数の畳み込みになっていて,この値は

(2NK2N1)(2NK2N)=K+12NK1(2NK1N)

であることが知られています.*5*6

したがって,2K+1(K+1)2NK1(2NK1N)となります.

対角線の下側しか通れないという制約が付いても,部分問題の解がCt1となるだけなのでK+12NK1(2NK1N)です.

この制約が付いた数え上げ問題ははカタラン数の畳み込みに帰着させる方法の他にも,下図のある直線を跨がない最短経路と一対一の対応をさせることでも求めることができます.ただし,「ある直線を跨がない最短経路」で説明したような直感的で簡潔な証明が分からないので省略します.

*7

K回曲がる最短経路

右折がK回ある最短経路

下図のような縦N区画,横M区画のグリッドの最短経路のうち,右折(↑→)の数を数えます.例えば以下の例ではN=4,M=6で右折回数は3回となります。

右折する地点を以下の青の点からK=3個選べば最短経路が一意に定まります.ただし,K点は左下から右上に並ぶように選ぶ必要があります(縦横に同じ列に2点や,点の左上の領域に点が存在してはいけません).

これは,下図の左の矢印からK個,下の矢印からK個選ぶことによって条件を満たす点を選ぶことができます.

例えば,最初の例に示した最短経路を選ぶ方法は下図のようになります.

したがって,このような経路数は(NK)(MK)となります.

形式的冪級数による解釈

最初に右に0回以上進み,右折をK回行って,最後に上に0回以上進む.
f=(x+x2+x3+)(y+y2+y3+)
fx=(1+x+x2+x3+)
fy=(1+y+y2+y3+)
としたときの[xNyM]fxfKfyが求める値.
1(1x)K+1=0i(K+iK)xiなので(NK)(MK)となる.

右左折がK回ある最短経路

右折(↑→)と左折(→↑)両方の数の和がKとなる最短経路の数を数えます.例えば以下の例ではK=5です.

まず,始点から最初に上()か右()どちらに進むかで別々に考えます.上に進む場合を考えると,右折回数はK2回,左折回数はK2回となります.最後の右折(左折)を無視する(Kによって最後どの列で右折(左折)するかは決まっているため)と,下図の左の矢印から右折する列をK12個,下の矢印から左折する列をK12個選ぶと最短経路が一意に定まります.

例えば,最初の例に示した最短経路を選ぶ方法は下図のようになります.

したがって,経路数は(N1K12)(M1K12)+(N1K12)(M1K12)となります.

形式的冪級数による解釈

最初に右に進む場合,右に1回以上進むのをK+12回,上に1回以上進むのをK+12回交互に繰り返すことになると考えると,右折がK回ある最短経路と同様に求めることができる.

左折がK回ある対角線を跨がない最短経路

縦横N区画のグリッド上の対角線を跨がない(下側のみを通る)最短経路のうち,左折(→↑)をK回行うものの数を数えます.

下図はN=6,K=3の経路の例です.

ここで,下図のように右へ進む場合と上へ進む場合を色分けして同じ色が連続している数を書いてみます.

右へ連続して進む区間と上へ連続して進む区間が交互にK回ずつ出現することがわかります.i番目に出現する「右へ連続して進む区間」の右に進む回数をaiとします.上へ進む場合も同様にして数列bを定義します.
上図の例だとa={2,2,2},b={1,3,2}となります.

整数列a,bの条件は

  • i=1Kai=i=1Kbi=N
  • ai,bi1
  • i=1jbii=1jai(j=1,2,,K)

となりますが,3番目の条件は無視すると数列a,bは,縦NK区画,横K1区画のグリッドの最短経路と対応が取れます.
具体的には,先ほどのa=2,2,2,b=1,3,2は以下の最短経路と対応が取れます.縦にK本の経路がありますが,右からi番目の経路では上へai1回進んでいます.
右側の数列bの例では,まずb11=0回上へ進んで右へ1回進み,b21=2回上へ進んで右へ1回進み,b31=1回上へ進んでいます.

ここで3番目の条件 i=1jbii=1jai(j=1,2,,K) を考えると,このグリッドの経路上において数列bを表す最短経路が数列aを表す最短経路の上に来ないことが条件であることがわかります.

これで交差しない最短経路の組で扱う問題と同じになったためLGV公式を用いて求めると1N(NK)(NK1)となります.これはNarayana数として知られています.

左折がK回ある直線を跨がない最短経路

より一般に,以下のように縦N区画,横M区画のグリッドの上からL区画にかけて下図のように直線がある場合,その直線を跨がない最短経路のうち,左折(→↑)がK回あるようなものの数を数えます.

左折がK回ある対角線を跨がない最短経路では,最初に右,最後に上に進むしかないため考えやすくなっていましたが,今回はそうではありません.

そこで,簡単に考えるために最初は右()に,最後は上()に進む場合の経路数f→↑(N,M,L,K)を数えます.
左折がK回ある対角線を跨がない最短経路と同様に考えると,以下の数列に対応付けられます.

  • i=1Kai=M
  • i=1Kbi=N
  • ai,bi1
  • i=1jbii=1jai+NL(j=1,2,,K)

これは,下図のグリッド上の同色点間の最短経路の組であって,青点間の最短経路が赤点間の最短経路の上に来ないようなものの数となります.

LGV公式を用いると,

f→↑(N,M,L,K)=(N1K1)(M1K1)(L1K)(N+ML1K2)

となります(ただし,LN,M).

次に,最初は右(),最後は右()に進む場合の経路数f→→(N,M,L,K)を数えます.

終点まで進んだ後に上に1移動することにすると下図のグリッド上で「最初は右()に,最後は上()に進む場合の経路」として数えることができます(最後の→↑によりK1増えることに注意).

ただし,このままでは下図のような経路も含まれてしまうのでこれらを引く必要があります.

f→→(N,M,L,K)=f→↑(N+1,M,L+1,K+1)f→↑(N,M,L,K+1)
=(N1K1)(M1K)(L1K)(N+ML1K1)

f↑↑(N,M,L,K)f→→(M,N,L,K)であるので,

f↑↑(N,M,L,K)=(N1K)(M1K1)(L1K)(N+ML1K1)

f↑→(N,M,L,K)を求めます.下図は最初は上にa進み,最後は右にb進んだ場合の経路を表しています.

最初のaステップと最後のbステップを除くとf→↑(Na,Mb,L,K)となります.

f↑↑(N,M,L,K)=a=LN1b=LM1f→↑(a,b,L,K)
=(N1K)(M1K)(L1K)(N+ML1K)

これまでの結果をまとめると以下のようになります.

  • f→↑(N,M,L,K)=(N1K1)(M1K1)(L1K)(N+ML1K2)
  • f→→(N,M,L,K)=(N1K1)(M1K)(L1K)(N+ML1K1)
  • f↑↑(N,M,L,K)=(N1K)(M1K1)(L1K)(N+ML1K1)
  • f↑→(N,M,L,K)=(N1K)(M1K)(L1K)(N+ML1K)

したがって,求める最短経路数はこれらの和なので,

(NK)(MK)(L1K)(N+ML+1K)

となります.

右折がK回ある直線を跨がない最短経路

同様に右折がK回ある場合も考えてみます.

最初が右(),最後が上()となる最短経路において,右折回数をKとすると左折回数はK+1となります.

最初が右(),最後が右()となる最短経路において,右折回数をKとすると左折回数はKとなります.

最初が上(),最後が上()となる最短経路において,右折回数をKとすると左折回数はKとなります.

最初が上(),最後が右()となる最短経路において,右折回数をKとすると左折回数はK1となります.

以上から,

f→↑(N,M,L,K+1)+f→→(N,M,L,K)+f↑↑(N,M,L,K)+f↑→(N,M,L,K1)
=(NK)(MK)(L+1K+1)(N+ML1K1)

となります.

右左折がK回ある直線を跨がない最短経路

同様に右左折がK回ある場合も考えてみます.

最初が右(),最後が上()となる最短経路において,右左折回数をKとすると左折回数はK+12となります.(Kは奇数)

最初が上(),最後が右()となる最短経路において,右左折回数をKとすると左折回数はK12となります.(Kは奇数)

最初が右(),最後が右()となる最短経路において,右左折回数をKとすると左折回数はK2となります.(Kは偶数)

最初が上(),最後が上()となる最短経路において,右左折回数をKとすると左折回数はK2となります.(Kは偶数)

以上から,

{(N1K2)(M1K21)+(N1K21)(M1K2)2(L1K2)(N+ML1K21)(K0(mod2))2(N1K12)(M1K12)(L1K12)(N+ML1K12)(L1K12+1)(N+ML1K121)(K1(mod2))

複数の最短経路数の和

複数の点間の最短経路数の和は一つずつ求めずとも簡単に求まる場合があります.ここでは,そのような例について見ていきます.

対角線上の点までの最短経路

下図のような縦横N区画のグリッドがあり,左下の点(黒)から対角線上の各点(オレンジ)までの最短経路数の総和を求めます.下図はN=6の例です.

この例では,最短経路数は左上の点から順に(60),(61),(62),(63),(64),(65),(66)なので答えは64です.

一般に,二項定理より(1+1)N=i=0N(Ni)であるので,総和は2Nになります.

傾き-q/pの直線上の点までの最短経路

さらに一般化して,左下を原点,右をx軸正の方向,上をy軸正の方向とする平面のy=qpx+N (p,qは互いに素)の直線上にある格子点までの最短経路数の総和を求めます.

下の図はN=5,p=2,q=3の例です.

結論のみ書きますが,形式的冪級数を用いて、

[xN](1x)p1(1x)pxq

となります.N=6,p=1,q=1の場合,対角線上の点までの最短経路の例のように64となることが分かります.

さらに,これを拡張して,直線を右にkずらし,点(k,N)を端点とする半直線上の格子点までの最短経路数の総和を考えます.以下はk=3の場合の例です.

これは累積和をk回取るだけなので,

[xN](1x)pk1(1x)pxq

と表されます.

グリッドの端の点までの最短経路

下図のような縦N区画,横M区画のグリッドがあり,左下の点(黒)からグリッドの端の各点(オレンジ)までの最短経路数の総和を求めます.下図はN=4,M=6の例です.

ここでグリッドの区画を右に増やします.そして各点を右の辺上に移動させます.このグリッドでの左下の点(黒)から各点(オレンジ)までの最短経路数の総和は元のグリッドでの最短経路数の総和と同じです.さらに,左下の点から右上の点(黒)への最短経路は必ずオレンジの点をただ一つ通るので,求める最短経路数の総和はこのグリッドでの左下の点から右上の点への最短経路数の総和と一致します.したがって,(N+M+1N)が答えとなります.

経路の上側の面積がKとなる最短経路

以下のように、赤い経路に対して,経路の上側の色が塗られたマスの数のことを,赤い経路に対する上側の面積とします.この例の場合,面積は10となります.

NMのグリッドで上側の面積がKとなるような最短経路の数は,簡単な対応付けにより「KN個以下の"M以下の非負整数"に分割する方法の数」であることが分かります.*8
単純な動的計画法ではO(NMK)かかりますが,q二項係数と形式的冪級数を利用するとO(KlogK)で求めることができます.(問題例のところに問題(Mojacoder)置いてます)

交差しない最短経路の組

N区画,横M区画のグリッドの最短経路のうち,互いに交差しないようなものK個の選び方を求めます.

ただし,2つの最短経路が交差するとは,以下のような状態のことを指すものとし,

以下のような不完全な交差(重なっているだけで上下が入れ替わっていないもの)は考えないものとします.

K=3のケースを用いて説明します.
以下のように最短経路をスライドすることによって,どの2つの最短経路も重なっていないようなものを数え上げる問題になります.

この問題はLGV公式を用いて解くことができ,答えは

i=0K1(N+M+i)!(i)!(N+i)!(M+i)!

となり,O(N+M+K)で求めることができます.

より詳しい解説はこの記事を参照してください.

ある領域を通らない最短経路

下図のような縦N区画,横M区画のグリッドがあり,左上の一部の領域を通らないような最短経路数を求めます.ただし,領域は図のように階段状になっている必要があり,領域の境界は通ってよいものとします.下図はN=6,M=7の例です.灰色の部分が通れない領域を示しています.

dpi,jを「上にi,右にj進んだ場所までの経路数」としたとき,単純な遷移ではO(NM)かかってしまいます.

通れる領域を真ん中付近で分割し,再帰的に求めていくことを考えます.以下のように,赤枠の部分を境目にしてオレンジの部分と水色の部分に分割されます.

オレンジの部分を再帰的に求めた後,以下の赤点の値が求まっています.赤点群の値から黄点群の値を求めることを考えます.詳しいことは書きませんが(TODO:書く),畳み込みができる形になっているため,分割統治FFTの要領でO((N+M)log2(N+M))で求めることができます.

左上だけでなく右下の領域も通れない場合は

以下のように領域を分割することで先程と同様に求めることができます.

ちなみに,これは簡単な対応付けにより以下のような問題に言い換えることができます.

以下の条件を満たす長さNの整数列A,Bが与えられる.

  • AiBi
  • 0A1A2ANM
  • 0B1B2BNM

AiCiBiを満たす長さNの広義単調増加整数列Cの数を求めよ.

Ai>Ai+1であってもAiAi+1としても問題ないので以下の問題も同様に解けます.

0以上M以下の整数からなる長さNの数列A,Bが与えられる.AiCiBiを満たす長さNの広義単調増加整数列Cの数を求めよ.

実装例

問題例