動的プログラミングに぀いお知りたいが、尋ねるのが怖かったすべおのこず

ハブに動的プログラミング以降、単にダむナミクスず呌びたすに関する蚘事がほずんどないこずに非垞に驚いた このパラダむムは、プログラミングオリンピックの枠を超えたものも含めお、非垞に広たっおいるように思えたした。 したがっお、この蚘事でこのギャップを埋めようずしたす。

#        Python 

基本


おそらく、私が今たで聞いた䞭で、ダむナミクスの最高の説明を1぀の文で曞いたものです。

動的プログラミングずは、解決方法が明確ではないタスクがあり、それをより小さなタスクに分割するこずであり、これも解決方法が明確ではありたせん。 cA.クモック。

ダむナミクスによっお問題を解決するには、次のものが必芁です。
1ダむナミクスの状態サブタスクを䞀意に指定するパラメヌタヌ。
2初期状態の倀。
3状態間の遷移再蚈算匏。
4再集蚈の手順。
5問題に察する答えの䜍眮これは時々合蚈、たたは、䟋えば、いく぀かの状態の倀の最倧倀です。

再蚈算手順


3぀の倉換オヌダヌがありたす。
1盎接泚文
状態は、すでに蚈算された状態に基づいお順次再蚈算されたす。



2逆順
珟圚の状態に応じお、すべおのステヌタスが曎新されたす。



3レむゞヌダむナミクス
ダむナミクスの再垰的メモ再蚈算機胜。 これは、゚ッゞがそれらの間の䟝存関係である非埪環状態グラフでのディヌプサヌチのようなものです。



基本䟋 フィボナッチ数 ステヌタス-番号。

盎接泚文
 fib[1] = 1 #   fib[2] = 1 #   for i in range(3, n + 1): fib[i] = fib[i - 1] + fib[i - 2] #   i 

逆順
 fib[1] = 1 #   for i in range(1, n): fib[i + 1] += fib[i] #   i + 1 fib[i + 2] += fib[i] #   i + 2 

レむゞヌダむナミクス
 def get_fib(i): if (i <= 2): #   return 1 if (fib[i] != -1): #  return fib[i] fib[i] = get_fib(i - 1) + get_fib(i - 2) #  return fib[i] 

3぀のオプションすべおに生呜暩がありたす。 それらはそれぞれ独自のスコヌプを持っおいたすが、倚くの堎合他のスコヌプず重耇しおいたす。

倚次元ダむナミクス


1次元のダむナミクスの䟋は、䞊蚘の「倉換の順序」で瀺されおいるため、すぐに倚次元から始めたす。 ご想像のずおり、1次元ずは異なり、枬定の数、぀たり状態のパラメヌタヌの数です。 これに基づく分類は通垞、「1察2」スキヌムに基づいおおり、実際には特に基本的ではありたせん。

倚次元ダむナミクスは1次元ずそれほど倉わりたせん。いく぀かの䟋を芋るずわかりたす。

䟋1SMSの数

以前は、電話機にボタンがあった堎合、キヌボヌドは次のようになりたした。



このようなキヌボヌドのタップをk回以䞋䜿甚しお、耇数のテキストメッセヌゞをいく぀曞くかを蚈算する必芁がありたす。

解決策
1ダむナミクス状態 dp[n][m] mタップを䜿甚した長さn異なるメッセヌゞの数。
2初期状態長されロのメッセヌゞが1぀あり、れロクリックを䜿甚しお-空。
3再蚈算匏1回、2回、3回のクリックが必芁な曞き蟌み甚の8文字ず、4回のクリックが必芁な2文字がありたす。

盎接再集蚈
 dp[n][m] = (dp[n - 1][m - 1] + dp[n - 1][m - 2] + dp[n - 1][m - 3]) * 8 + dp[n - 1][m - 4] * 2 
カりントダりン
 dp[n + 1][m + 1] += dp[n][m] * 8 dp[n + 1][m + 2] += dp[n][m] * 8 dp[n + 1][m + 3] += dp[n][m] * 8 dp[n + 1][m + 4] += dp[n][m] * 2 

4倉換手順
盎接曞く堎合、たずえば、小さなmは存圚しないかもしれないdp[n - 1][m - 4]に向かうずき、ダむナミクスの境界を越えるこずに぀いお別に考える必芁がありたす。 これを回避するには、䞭立的な芁玠答えを倉曎しないに関しおチェックを蚭定するか、曞き留めたす。

再集蚈を䜿甚するず、すべおがよりシンプルになりたす。ネガティブな芁玠に陥らないように、垞に前を向いおいたす。

5答えはすべおの州の合蚈です。

UPD
残念なこずに、私は間違いを犯したした-状態からメッセヌゞnの長さを取り陀くだけで、問題を1次元で解決できたす。
1ステヌタス dp[m] m回のクリックで入力できるさたざたなメッセヌゞの数。
2初期状態 dp[0] = 1
3再蚈算匏
 dp[m] = (dp[m - 1] + dp[m - 2] + dp[m - 3]) * 8 + dp[m - 4] * 2 
4順序3぀のオプションすべおを䜿甚できたす。
5答えはすべおの州の合蚈です。

䟋2銬

チェスの銬は、サむズN x Mボヌド䞊のケヌゞ(1, 1)に立っおいたすM セル(N, M)に到達する方法の数を4぀のタむプのステップでカりントする必芁がありたす。



解決策
1ダむナミクス状態 dp[i][j] - (i, j)に到達する方法の数。
2初期倀セル(1, 1)䞀方向で到達できたす-䜕もしたせん。
3再蚈算匏
盎接泚文の堎合
 dp[i][j] = dp[i - 2][j - 1] + dp[i - 2][j + 1] + dp[i - 1][j - 2] + dp[i + 1][j - 2] 
逆順の堎合
 dp[i + 1][j + 2] += dp[i][j] dp[i + 2][j + 1] += dp[i][j] dp[i - 1][j + 2] += dp[i][j] dp[i + 2][j - 1] += dp[i][j] 

4そしお今、このタスクで最も興味深い郚分は、順序です。 ここでは、行や列だけを移動するこずはできたせん。 それ以倖の堎合は、ただ再蚈算されおいない状態を盎接の順序で参照し、未完成の状態を逆のアプロヌチで取埗するためです。

2぀の方法がありたす。
1適切な回避策を考え出したす。
2レむゞヌダむナミクスを実行し、圌女にそれを理解させたす。

あなたが考えるのが面倒な堎合-怠dynamicなダむナミクスを実行するず、それは完璧に仕事をしたす。
怠lazでなければ、次のような回避策を考えるこずができたす。



この順序により、盎接ラりンドの各ステップで必芁なすべおのセルの凊理ず、反察の珟圚の状態の凊理が保蚌されたす。

5答えは単にdp[n][m]たす。

ダむナミクスず遷移マトリックス


行列を乗算したこずがないが、この芋出しを理解したい堎合は、少なくずもwikiを読む必芁がありたす 。

䟋えば、氞遠のフィボナッチ数など、動的蚈画法によっおすでに解決した問題があるず仮定したす。
少し䜜り盎したしょう。 ベクトルがありたすか ベクトルの取埗元 。 数匏を少し開いおみたしょう。 。 あなたはベクトルからそれを芋るこずができたす ベクトルを取埗できたす 最初のベクトルの折り畳たれた倉数のみが最終ベクトルに衚瀺されるため、䜕らかの皮類の行列を乗算したす。 このマトリックスは簡単に導き出せたす。ここにありたす 。 これを遷移行列ず呌びたす。

これは、ベクトルを取る堎合 遷移行列をn - 1回乗算するず、ベクトルが埗られたす 、 fib[n] -問題ぞの答え。

そしお今、なぜこれがすべお必芁なのか。 行列の乗算には結合性の特性がありたす。 しかし、これには可換性がありたせん。これは私の意芋では驚くべきこずです。 このプロパティは、これを行う暩利を䞎えたす。 。

これは、高速环乗法を適甚できるためです。 。 合蚈で、算術挔算の察数のNフィボナッチ数を蚈算するこずができたした。

そしお今、䟋はより深刻です

䟋3ノコギリシヌケンス

長さNのこぎり波シヌケンスを、極端でない各芁玠に察しお条件が満たされるシヌケンスずしお瀺したす。それは、その2぀の近傍よりも小さいか、それ以䞊です。 長さNの数字の鋞歯状シヌケンスの数を蚈算する必芁がありたすN 次のようになりたす。


解決策
たず、遷移行列のない゜リュヌション

1ダむナミクス状態 dp[n][last][less] - last桁で終わる長さnのこぎり歯列の数。 そしお、 less == 0堎合、最埌の桁は最埌から2桁より小さく、 less == 1堎合、それより倧きくなりたす。
2初期倀
 for last in range(10): dp[2][last][0] = 9 - last dp[2][last][1] = last 
3ダむナミクスの再蚈算
 for prev in range(10): if prev > last: dp[n][last][0] += dp[n - 1][prev][1] if prev < last: dp[n][last][1] += dp[n - 1][pref][0] 
4再蚈算の順序垞に以前の長さを参照するため、のネストさforたカップルのみです。
5答えは合蚈dp[N][0..9][0..1]です。

ここで、初期ベクトルずそれに察応する遷移行列を䜜成する必芁がありたす。 ベクトルはすぐに発明されたようです。すべおの状態はシヌケンスN長さを瀺したすN さお、倉換匏を芋お、遷移行列が導出されたす。

ベクトルず遷移行列

サブセグメントダむナミクス


これは、状態が配列のサブセグメントの境界であるダむナミクスクラスです。 䞀番䞋の行は、配列のすべおの可胜なサブセグメントに基づいおサブタスクの回答を蚈算するこずです。 通垞、それらは長さの増加順に゜ヌトされ、蚈算はそれぞれ短いセグメントに基づいおいたす。

䟋4文字列のパック

これが展開された状態です。 簡単にもう䞀床蚀いたす。

圧瞮された行を定矩したす。
1文字のみで構成される文字列は、圧瞮された文字列です。 圌女は自分自身を開きたす。
22぀の圧瞮された文字列AずB連結した文字列 展開された行AずBを連結するために展開されたすB
3文字列D(X) 、ここでDは1より倧きい敎数、 Xは圧瞮された文字列です。 Xから圧瞮解陀されたD文字列の連結に圧瞮解陀されたすX
䟋 “3(2(A)2(B))C” “AABBAABBAABBC”展開されたす。

行s展開される最短の圧瞮行の長さs芋぀ける必芁がありたす。

解決策
この問題は、おそらく既に掚枬されおいるように、サブセグメントのダむナミクスによっお解決されおいたす。

1ダむナミクス状態 d[l][r] -文字列s[l:r]展開される最小長の圧瞮文字列
2初期状態長さ1のすべおの郚分文字列は、その䞭でのみ圧瞮できたす。
3ダむナミクスの再蚈算
最良の答えは、ある皮の最終的な圧瞮操䜜です。それは単に倧文字の文字列であるか、2行の連結であるか、圧瞮そのものです。 それでは、すべおのオプションを調べお、最適なものを遞択したしょう。

 dp_len = r - l dp[l][r] = dp_len #    -  . for i in range(l + 1, r): dp[l][r] = min(dp[l][r], dp[l][i] + dp[i][r]) #       for cnt in range(2, dp_len): if (dp_len % cnt == 0): #   ,      good = True for j in range(1, (dp_len / cnt) + 1): #   ,   cnt   good &= s[l:l + dp_len / cnt] == s[l + (dp_len / cnt) * j:l + (dp_len / cnt) * (j + 1)] if good: #    cnt     dp[l][r] = min(dp[l][r], len(str(cnt)) + 1 + dp[l][l + dp_len / cnt] + 1) 
4再カりントの手順サブストリングの盎接昇順たたは遅延ダむナミクス。
5答えはd[0][len(s)]たす。

䟋5 オヌクス

サブツリヌダむナミクス


サブツリヌに沿ったダむナミクスの状態のパラメヌタヌは、通垞、この頂点がルヌトであるサブツリヌを瀺す頂点です。 珟圚の状態の倀を取埗するには、通垞、すべおの子䟛の結果を知る必芁がありたす。 ほずんどの堎合、圌らはそれを遅延的に実装したす-圌らは単に朚の根から深さで怜玢を曞きたす。

䟋6論理ツリヌ

䞭断されたツリヌが䞎えられた堎合、そのリヌフにはシングルビット番号0たたは1が含たれたす。 数倀はすべおの内郚頂点にも曞き蟌たれたすが、次のルヌルに埓っお、各頂点に察しお論理挔算の1぀が遞択されたす「AND」たたは「OR」。 「AND」の堎合、ピヌクの倀はそのすべおの子の倀の論理「AND」です。 「OR」の堎合、頂点の倀はそのすべおの子の倀の論理「OR」です。



ルヌトの倀が倉曎されるか、䞍可胜であるこずを通知するように、内郚頂点での論理挔算の最小倉曎数を芋぀ける必芁がありたす。

解決策
1ダむナミクス状態 d[v][x] -頂点vでxの倀を取埗するために必芁な操䜜の数。 これが䞍可胜な堎合、状態倀は+infです。
2初期倀葉の堎合、倉曎がれロの堎合に倀を取埗できるこずは明らかですが、倀を倉曎するこずはできたせん。぀たり、 +inf操䜜に察しおのみ可胜です。
3再蚈算匏
頂点の倀がすでにxである堎合、れロです。 そうでない堎合、2぀のオプションがありたす。珟圚の頂点で操䜜を倉曎するかどうかです。 どちらの堎合も、最適なオプションを芋぀けお最適なものを遞択する必芁がありたす。

「And」操䜜で「0」を取埗する必芁がある堎合、答えは倀d[i][0]の最小倀です。ここで、 iはvの息子です。
「And」操䜜で「1」を取埗する必芁がある堎合、答えはすべおの倀d[i][1]の合蚈です。ここで、 iはvの息子です。
操䜜が「OR」で、「0」を取埗する必芁がある堎合、答えはすべおの倀d[i][0]の合蚈です。ここで、 iはvの息子です。
操䜜が「OR」で、「1」を取埗する必芁がある堎合、答えは倀d[i][1]の最小倀です。ここで、 iはvの息子です。

4再蚈算順序最も簡単に遅延的に実装されたす-ルヌトからの深さの怜玢の圢匏で。
5答えはd[root][value[root] xor 1]です。

サブセットダむナミクス


サブセット䞊のダむナミクスでは、特定のセットのマスクが通垞状態になりたす。 それらは、このマスクのナニット数が増加する順序で最も頻繁に遞択され、包含の小さい状態からそれぞれ再カりントされたす。 回避策を特に考えないように、通垞は怠dynamicなダむナミクスが䜿甚されたすが、これは完党に些现なこずではありたせん。

䟋7最小重量のハミルトニアンサむクル、たたは巡回セヌルスマン問題

サむズN重み付き゚ッゞの重みが負でないグラフG䞎えられた堎合 最小重みのハミルトニアンサむクル 自己亀差なしですべおの頂点を通過するサむクルを芋぀けたす。

解決策
すべおの頂点を通過するサむクルを探しおいるので、「初期」頂点に任意のものを遞択できたす。 それを頂点番号0たす。

1ダむナミクス状態 dp[mask][v] -頂点0から頂点vたでの最小重みのパス。 maskあり、それらに沿っおいるすべおの頂点を通過したす。
2初期倀 dp[1][0] = 0 、最初は他のすべおの状態- +inf 。
3再蚈算匏 maskのi番目のビットが1 、 iからvぞの゚ッゞがある堎合
 dp[mask][v] = min(dp[mask][v], dp[mask - (1 << i)][i] + w[i][v]) 
ここで、 w[i][v]はiからvたでの゚ッゞの重みです。
4倉換手順最も簡単で最も䟿利な方法は、レむゞヌダむナミクスを蚘述するこずですが、マスクの列挙を歪めお蚘述しお、その䞭の単䞀ビットの数を増やすこずができたす。
5答えはd[(1 << N) - 1][0]たす。

プロファむルダむナミクス


プロファむルに沿ったダむナミクスによっお解決される叀兞的な問題は、いく぀かの数字でフィヌルドを䞊べるタスクです。 さらに、たずえば、タむリングの方法の数、たたは最小数の数字でタむリングするなど、さたざたなこずが求められる堎合がありたす。

これらのタスクは、 ここでaは1぀のセルのタむリングのバリアントの数です。 プロファむルに沿ったダむナミクスは、いずれかの次元の時間を線圢に最適化し、係数のみを指数関数的に残したす。 次のようなものが埗られたす。 。

プロファむルはk列倚くの堎合1列で、既にタむル化されおいる郚分ずただタむル化されおいない郚分ずの境界です。 この境界は郚分的にしか塗り぀ぶされおいたせん。 非垞に倚くの堎合、ダむナミクスの状態の䞀郚です。



ほずんどの堎合、状態はプロファむルであり、このプロファむルの堎所です。 そしお、移行により、この堎所が1぀増えたす。 プロファむルサむズに比䟋した時間で、あるプロファむルから別のプロファむルに切り替えるこずができるかどうかを確認できたす。 これは再カりント䞭に毎回確認できたすが、カりントするこずもできたす。 2次元配列can[mask][next_mask]をカりントしたす。耇数の図圢を配眮しお、プロファむルの䜍眮を1぀ず぀増やすこずで、あるマスクから別のマスクに移動できたす。 カりントするず、実行時間が短くなり、メモリが増えたす。

䟋8ドミノの支配

1 x 2および2 x 1寞法のドミノを䜿甚しお、テヌブルN x Mをブリッゞする方法の数を芋぀けたす。

解決策
ここでは、プロファむルは単䞀の列です。 0タむル化されおいない列セル、 1タむル化されたバむナリマスクの圢匏で保存するず䟿利です。 ぀たり、合蚈プロファむル 。

0事前蚈算オプションプロファむルのすべおのペアを反埩凊理し、あるプロファむルから別のプロファむルに移行できるこずを確認したす。 このタスクでは、これは次のように怜蚌されたす。

次の堎所の最初のプロファむルが1の堎合、2番目のプロファむルでは0でなければなりたせん0これは、このセルを数字で埋めるこずができないためです。

次の堎所の最初のプロファむルが0堎合、2番目の0たたは1 2぀のオプションがありたす。
0堎合、これは垂盎ドミノを配眮する矩務があるこずを意味したす。぀たり、次のセルを1ず芋なすこずができたす。 1堎合、垂盎ドミノを配眮し、次のセルに移動したす。

遷移の䟋䞊のプロファむルから䞋の遷移に移動できたす



その埌、すべおを配列に保存can[mask][next_mask] 1 、行くこずができる堎合、 0できない堎合。
1ダむナミクスの状態 dp[pos][mask] -最初のpos - 1完党なタむルの数pos - 1プロファむルmask pos - 1列。
2初期状態 dp[0][0] = 1フィヌルドの巊の境界は盎線の壁です。
3再蚈算匏
 dp[pos][mask] += dp[pos - 1][next_mask] * can[mask][next_mask] 

4バむパス順posの増加順。
5答えはdp [pos] [0]にありたす。

結果の挞近は 。

壊れたプロファむルダむナミクス


これは、プロファむルのダむナミクスの非垞に匷力な最適化です。 ここでは、プロファむルはマスクだけでなく、骚折郚䜍でもありたす。 次のようになりたす。



これで、プロファむルにキンクを远加した埌、キンクの巊のセルをカバヌする1぀の図のみを远加しお、次の状態に進むこずができたす。 ぀たり、状態数をN倍に増やすこずでブレヌクがどこにあるかを芚えおおく必芁がありたす、1぀の状態から別の状態ぞの遷移の数を枛らしたす。 前に 。 挞近性の改善 前に 。

ドミノのタむル匵りの問題の䟋䟋8による、砎損したプロファむルに沿ったダむナミクスの遷移



回答の回埩


ベストアンサヌの特性を知るだけでは䞍十分な堎合がありたす。 たずえば、「文字列のパッキング」タスク䟋4では、圧瞮された最短の文字列の長さだけで終わりたすが、ほずんどの堎合、その長さではなく、文字列自䜓が必芁です。 この堎合、答えを埩元する必芁がありたす。

各タスクには答えを埩元する独自の方法がありたすが、最も䞀般的な方法は次のずおりです。


マむナヌな最適化


蚘憶

倚くの堎合、ダむナミクスでは、状態がカりントされる他の状態を非垞に倚く必芁ずしないずいう問題に察凊できたす。 たずえば、フィボナッチ数を蚈算するずき、最埌の2぀だけを䜿甚し、前の数に戻るこずはありたせん。 したがっお、それらに぀いおは忘れるこずができたす。぀たり、メモリに保存しないでください。 これにより、挞近的メモリ掚定が改善される堎合がありたす。 この手法は、䟋1、2、3遷移マトリックスなしの゜リュヌション、7、8で䜿甚できたす。 確かに、バむパスの順序が遅延ダむナミクスの堎合、これはたったく機胜したせん。

時間

ある皮のデヌタ構造を䜿甚しお挞近時間を改善できる堎合がありたす。 たずえば、 ダむクストラのアルゎリズムでは、 優先床キュヌを䜿甚しお挞近時間を倉曎できたす。

状態の眮換


決定においお、ダむナミクスには垞に状態が含たれたす。これは、サブタスクを䞀意に指定するパラメヌタヌですが、必ずしもこの状態が唯䞀の状態ではありたせん。堎合によっおは、他のパラメヌタを思い぀いお、挞近的な時間たたは蚘憶の枛少ずいう圢でこの恩恵を受けるこずができたす。

䟋9数倀の分解

数Nをさたざたな甚語に分解する数を芋぀ける必芁がありたす。たずえば、の堎合N = 7、そのような展開5

状態の異なる2぀の゜リュヌション
№1:

1) : dp[n][k] — n , k . k , , .
2) : dp[1][1] = 1 , dp[1][i] = 0 .
3) :
 for last_summand in range(1, k + 1): dp[n][k] += dp[n - last_summand][last_summand] 

4) : , n .
5) — dp[N][1..N] .

: , : 。 挞近 。

№2:

1) . dp[n][k] — n k . , .
2) : dp[1][1] = 1 , dp[1][i] = 0 .
3) :
 dp[n][k] = dp[n - k][k] + dp[n - k][k - 1] 

, . ( ) :
  • 1 .
  • 1 . 1 .

, :


.

, — . — , , — : .

4) : , n .

, , . , — k N , ( 1 k ). , 。

5) — dp[N][1..k_max] .

挞近 。

おわりに


䞻な情報源は校長で、情報はサマヌコンピュヌタヌスクヌル児童向けでの講矩、アンドレむスタンケビッチのサヌクル、ミハむルドノォルキンdarnleyの特別コヌスから埗られたした。

ご枅聎ありがずうございたした。この蚘事が誰かに圹立぀こずを願っおいたす私は䟿利になりたしたが、蚘事を曞くこずはすべおを芚える良い方法であるこずがわかりたした。

Source: https://habr.com/ru/post/J191498/


All Articles