Max値取得|動的計画法( DP )
動的計画法 ( DP )の学習として解きました。
例題のねらい:動的計画法におけるメモ配列とDPテーブルの違いを確認する。
問題: 要素の int 型配列 が与えられる. の最大値を DP で求めよ
問題制約は特になかったので、適当に。( くらい?)
1. メモ化再帰編
正当性の証明
計算量
main 関数は std::vector::resize に 、再帰関数の呼び出しに 時間。
rec 関数は、訪問済判定の if 文、訪問済だった場合、memo した値を返すのにそれぞれ 時間。
基底ケース部分は、 if 文、res を返すのにそれぞれ 時間。再帰ケース部分は std::max *1 を使って大小比較 1 回につき 時間かかり、それを再帰関数 で 回繰り返すので 時間。プログラム全体では 時間。
コード
vector<int> memo( 100000 + 1, -1 ); int N, res; vector<int> A; int rec( int i ) { int &res = memo[ i ]; if( res != -1 ) { return res; } //基底ケース if( i == 1 ) { return res = A[ 0 ]; } //再帰ケース return res = max( rec( i - 1 ), A[ i - 1 ] ); } int main() { cin >> N; A.resize( N ); for( auto &x : A ) { cin >> x; } cout << rec( N ) << endl; return 0; }
実行コード:[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
2. Loop DP 編
次にメモ化再帰編を元に Loop DP 版を書きました。
計算量
DP 部分は std::max を使っての大小比較 1 回につき 時間を loop で 回繰り返すので、 時間。
プログラム全体では 時間となる。
int main() { int N; cin >> N; vector<int> A( N ); for( auto &x : A ) { cin >> x; } vector<int> dp( 100000 + 1 ); dp[ 1 ] = A[ 0 ]; for( int i = 2; i <= N; i++ ) { dp[ i ] = max( dp[ i - 1 ], A[ i - 1 ] ); } cout << dp[ N ] << endl; return 0; }
実行コード:[Wandbox]三へ( へ՞ਊ ՞)へ ハッハッ
3. 学習まとめ
メモ化再帰も loop DP も計算結果を保存して次の計算に使うという本質的な所は同じで、単に実装方法が異なるだけということが例題から良く判りました(おわり)