速いそれを作る、右のそれを作る、それを動作させます。 - ケント・ベック
ここでは最初の2つの文は、一回の反復の後に言うことですつまり、再帰的であると言います。書き込みに本当に簡単再帰大法を認めざるを得ないが、反復法は、より効率的かつ高速です。
動的プログラミングは、奇妙に聞こえるかもしれないが、他の言葉では、再帰は、反復的に書き込みした後、予備的な結論に来ます。
例えば、古典的なフィボナッチ数列を取ります
長い長いフィボナッチ(int型N){
IF(N == 0){ リターン1。 } そうであれば(N == 1){ 1を返します。 } 他{ 戻りフィボナッチ(N - 1)+フィボナッチ(N - 2)。 } } // T(N)= POW(2 N - 1)= O(POW(2、n))を
私たちは、それに応じて再帰をトレースしたいです:
この再帰的なツリーが重複枝をたくさん持っている中で私たちは見ることができますので、我々は、重複支店にカットすることができますか?
改善されたファースト:再帰のメモリ
長い長いフィボナッチ(INT N){ 長い長いF [100] = {0}。 IF(N == 0){ 戻りF [0] = 0; } そうであれば(N == 1){ 戻りF [1] = 1。 } そうであれば(F [N]){ 戻りF [N]。 } 他{ 戻りF [N] =フィボナッチ(N - 1)+フィボナッチ(N - 2)。 } } // T(N)= POW(2、N - 2)= O(POW(2、n))を
重複した枝を削除するが、しかし、複雑さが大幅に下落していないようです
改善II:動的プログラミング(非再帰的)
長い長いフィボナッチ(int型N){ 長い長いF [100]。 F [0] = 0; F [1] = 1。 以下のために(; <I = N;整数iが2 = I ++){ F [I] = F [I - 1] + F [I - 2]。 } [N] Fリターン。 } // T(N)= O(N)
2アイデア上記の上から下へこのアルゴリズムの変更、我々は通常問題(イテレーション)を解決することを好む思考、思考のボトムアップの方法を取っている間。
そしてまた、私は、動的プログラミングの冒頭で述べた再帰は、反復の形式に変換した予備的な結論を出すに使用することで撮影する必要があります。
動的プログラミング述べたように、典型的な例です。
LCS(最長共通部分)//最長共通部分列
シーケンス:順序に並べた文字列が抽出され、いくつかの文字は、文字列から抽出されます
最長共通部分列:2つの共通のサブ最長
例:D IDAC
アドバン
最長共通部分列:ダ
このような問題に直面して、私たちの従来の考え方は以下のとおりです。
共通サブシーケンスを特定する1
2.そして、最長共通部分列を見つけます
動的なプログラミングのアイデアは、次のとおりです。
行列の中にすべてのサブ問題を想像してみて
行列会います:
(1)(I == 0 || J == 0)A [i]は[J] = 0の場合
(2)もし(I、J> 0 && CI == Rjの)A [i]は[J] = A [I - 1] [J - 1] + 1
(3)(I、J> 0 && CI = Rjと!)MAX(A [i]が[J - 1]、A [I - 1] [J])場合
書式#include <iostreamの> の#include <cstdioを> する#include <アルゴリズム> 書式#include <cmath> の#include <文字列> std名前空間を使用しました。 メイン(){int型 、文字列STR1 = "didacを"; 文字列STR2 = "ADVAN"。 INT A [7] [7] = {0}。 int型最長= 0; 以下のために(INT I 0 =; I <= str1.length(); I ++){ ため(INT J = 0であり、j <= str2.length(); J ++){ IF(I == 0 || J == 0 ){ A [I] [J] = 0; } そうなら(I> 0 && J> 0 && 0009 [I - 1] == STR2 [J - 1]){ A [I] [J] = A [I - 1] [J - 1] + 1。 } それ以外の場合(I> } } } のために(INT I 0 =; I <= str1.length(); I ++){ ため(INT J = 0であり、j <= str2.length(); J ++){ COUT << A [i]は[J ]; } COUT << ENDL。 } 0を返します。 }
概要:それはテーブルビューから、またはビュー行列規則の点からのものであるかどうか、マトリックス中の最大の要素である共通のサブシーケンス、および共通配列の最初の要素の最小数の最小増加の長さは、列と行の要素数です。
長い長いフィボナッチ(int型N){
IF(N == 0){ リターン1。 } そうであれば(N == 1){ 1を返します。 } 他{ 戻りフィボナッチ(N - 1)+フィボナッチ(N - 2)。 } } // T(N)= POW(2 N - 1)= O(POW(2、n))を
私たちは、それに応じて再帰をトレースしたいです:
この再帰的なツリーが重複枝をたくさん持っている中で私たちは見ることができますので、我々は、重複支店にカットすることができますか?
改善されたファースト:再帰のメモリ
長い長いフィボナッチ(INT N){ 長い長いF [100] = {0}。 IF(N == 0){ 戻りF [0] = 0; } そうであれば(N == 1){ 戻りF [1] = 1。 } そうであれば(F [N]){ 戻りF [N]。 } 他{ 戻りF [N] =フィボナッチ(N - 1)+フィボナッチ(N - 2)。 } } // T(N)= POW(2、N - 2)= O(POW(2、n))を
重複した枝を削除するが、しかし、複雑さが大幅に下落していないようです
改善II:動的プログラミング(非再帰的)
長い長いフィボナッチ(int型N){ 長い長いF [100]。 F [0] = 0; F [1] = 1。 以下のために(; <I = N;整数iが2 = I ++){ F [I] = F [I - 1] + F [I - 2]。 } [N] Fリターン。 } // T(N)= O(N)
2アイデア上記の上から下へこのアルゴリズムの変更、我々は通常問題(イテレーション)を解決することを好む思考、思考のボトムアップの方法を取っている間。
そしてまた、私は、動的プログラミングの冒頭で述べた再帰は、反復の形式に変換した予備的な結論を出すに使用することで撮影する必要があります。
動的プログラミング述べたように、典型的な例です。
LCS(最長共通部分)//最長共通部分列
シーケンス:順序に並べた文字列が抽出され、いくつかの文字は、文字列から抽出されます
最長共通部分列:2つの共通のサブ最長
例:D IDAC
アドバン
最長共通部分列:ダ
このような問題に直面して、私たちの従来の考え方は以下のとおりです。
共通サブシーケンスを特定する1
2.そして、最長共通部分列を見つけます
動的なプログラミングのアイデアは、次のとおりです。
行列の中にすべてのサブ問題を想像してみて
行列会います:
(1)(I == 0 || J == 0)A [i]は[J] = 0の場合
(2)もし(I、J> 0 && CI == Rjの)A [i]は[J] = A [I - 1] [J - 1] + 1
(3)(I、J> 0 && CI = Rjと!)MAX(A [i]が[J - 1]、A [I - 1] [J])場合
書式#include <iostreamの> の#include <cstdioを> する#include <アルゴリズム> 書式#include <cmath> の#include <文字列> std名前空間を使用しました。 メイン(){int型 、文字列STR1 = "didacを"; 文字列STR2 = "ADVAN"。 INT A [7] [7] = {0}。 int型最長= 0; 以下のために(INT I 0 =; I <= str1.length(); I ++){ ため(INT J = 0であり、j <= str2.length(); J ++){ IF(I == 0 || J == 0 ){ A [I] [J] = 0; } そうなら(I> 0 && J> 0 && 0009 [I - 1] == STR2 [J - 1]){ A [I] [J] = A [I - 1] [J - 1] + 1。 } それ以外の場合(I> A [i]は[J] = MAX(A [I - 1] [J]、A [i]は[J - 1])。 } } } のために(INT I 0 =; I <= str1.length(); I ++){ ため(INT J = 0であり、j <= str2.length(); J ++){ COUT << A [i]は[J ]; } COUT << ENDL。 } 0を返します。 }
概要:それはテーブルビューから、またはビュー行列規則の点からのものであるかどうか、マトリックス中の最大の要素である共通のサブシーケンス、および共通配列の最初の要素の最小数の最小増加の長さは、列と行の要素数です。