部分配列で、その和が最大になるものを求める〜その4〜
最後に、走査アルゴリズムというのを実装してみました。
例によって詳細は「珠玉のプログラミング」に載っているのですが、簡単に説明すると、
x[0...n]までの部分配列の最大和は、x[0...n-1]の部分配列の最大和か、x[n]から左方向に伸びた配列の和のいずれかである。
という考えにもとづいたものです。
これを利用して解くのが、次に示す走査アルゴリズムのコードです。
#include <iostream> #include <boost/random.hpp> #include "autoStopWatch.h" using namespace std; using namespace boost; const int ARRAY_LENGTH = 1000000; float x[ARRAY_LENGTH]; float max(float f1, float f2, float f3){ return max(f1, max(f2, f3)); } //和の最大を求める関数:走査アルゴリズム float maxSoFar(float x[], int length){ float maxsofar = 0; float maxendinghere = 0; for(int i = 0; i < length; i++){ maxendinghere = max(0.0f, maxendinghere + x[i]); maxsofar = max(maxsofar, maxendinghere); } return maxsofar; } int main(){ //ランダムな配列生成 { mt19937 gen; uniform_real<float> dst(-100, 100); variate_generator<mt19937, uniform_real<float> > rand(gen, dst); for(int i = 0; i < ARRAY_LENGTH; i++){ x[i] = rand(); } } { AutoStopWatch sw; float maxsofar = maxSoFar(x, ARRAY_LENGTH);//計算 cout << maxsofar << endl;//答え出力 } return 0; }
これまた、テキトーに時間測定してます。
自分のコードで、正確な処理時間比較はしていないけれども、
配列の要素数がすんごい大きいものを取り扱った場合、最初のアルゴリズムで41年かかる計算が、最後のアルゴリズムだと48ミリ秒で計算できるそうな。すごひ!
アルゴリズムによって、こんなにも計算速度が変わるものなんかと、びっくりした。