A229037 の最初の値を計算するというコードゴルフチャレンジのために、次の(無記号の)Haskellプログラムを作成しました。
これは、番目の値を計算するために提案するソリューションです。
a n | n<1 = 0
| n<3 = 1
| otherwise = head (goods n)
goods n = [x | x <- [1..], isGood x n]
isGood x n = and [ x - a(n-k) /= a(n-k) - a(n-k-k) || a(n-k-k) == 0 | k <- [1..n] ]
Haskellはこれらの値を自動的にキャッシュまたはメモしないことに注意してください。
シーケンスのOEISページはであることを示しています。したがって、アルゴリズムはより大きい到達しないため、で置き換えることができます。。x n + 1[1..]
[1..(n+1)/2]
関数呼び出しをカウントしようとして、次の上限を導出しました。これは、アルゴリズムが入力取る関数呼び出しの数です。n
最終的な式をMathematicaにプラグインしました:
RSolve[{T[n] == 2*T[n - 1]*n*(n + 1), T[1] == 1}, T[n], n]
そして、少し簡略化した後:
これとHaskellプログラムの実行時間の平均比率は、で あり、比率の標準偏差は約です。(奇妙なことに、比率の対数プロットは直線のように見えます)。2.0 ⋅ 10 39 6.0 ⋅ 10 39
定義する最初の線との比率は、それぞれと平均と標準偏差を持っていますが、そのプロットは大きく飛び回っています。
このアルゴリズムの時間の複雑さをより適切に把握するにはどうすればよいですか?
以下は、有効なC(マイナスの宣言を差し引いたもの)のアルゴリズムです。これは、Haskellコードとほぼ同等であると私は考えています。
int a(int n){
if (n < 1) {
return 0;
} else if (n < 3) {
return 1;
} else {
return lowestValid(n);
}
}
int lowestValid(int n){
int possible = 1; // Without checking, we know that this will not exceed (n+1)/2
while (notGood(possible, n)) {
possible++;
}
return possible;
}
int notGood(int possible, int n){
int k = 1;
while (k <= n) {
if ( ((possible - a(n-k)) == (a(n-k) - a(n-2*k))) && (a(n-2*k) != 0) ) {
return 1;
} else {
k++;
}
}
return 0;
}
Cバージョンは計算に約5分かかり、Haskellバージョンはとほぼ同じです。a (19 )
最初のバージョン:
Haskell: [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0e-2,3.0e-2,9.0e-2,0.34,1.42,11.77,71.68,184.37,1815.91]
C: [2.0e-6, 1.0e-6, 1.0e-6, 2.0e-6, 1.0e-6, 6.0e-6, 0.00003,0.00027, 0.002209, 0.005127, 0.016665, 0.080549, 0.243611, 0.821537, 4.56265, 24.2044, 272.212]
タグとタイトルを変更して、これがアルゴリズム分析であり、複雑性理論の問題ではないことを明確にしました。「掛け算と足し算が無視できると仮定する」- できますか?ほんと?あなたがほとんどのものを数えていない可能性があるので、あなたが数えているものを言う方が良いです。参照用の質問もご覧ください。
—
ラファエル
実際のメジャー実行時間に対して結果を(一定の係数で)プロットしてみましたか?(それは比率をプロットし、それが中に何かに収束した場合に推測することは、しばしば、より有益だ。)のためのansatz以来、私はここに助けにハードそれを見つける、言ったここではない、誰もが話している、ハスケルの細目に依存。具体的には、このセットの理解度はどのように評価されますか?されるメモ化されていますか?厳密な分析に必要なだけ実際に発生することを公開する疑似コードバージョンを含めると、より良い答え(または実際には!)が得られる場合があります。
—
ラファエル
a
最後に、フィッティング法を使用してランダウ境界を導出することはおそらく無駄です。そのような関数は、固定された関数のセットに対してのみ適合します。Mathematicaがそこで最悪の指数関数モデルを使用していたため、超指数関数的な成長を捉えるのはうまくいかなかったと思います。
—
ラファエル
@Raphaelあなたのコメントはとても役に立ちました。時間があれば、もっと詳しく調べます。また、は値の対数を直線に当てはめたものであり、これは何よりも暗闇の中でのショットでした。
—
Michael Klein