ゼッケンドルフの定理をC++で実装:隣り合わないフィボナッチ数の和への分解プログラム
本記事では、与えられた合計値が「互いに隣り合わないフィボナッチ数」の和として表現できるかどうかを判定し、表せる場合には実際にどの数値の組み合わせになるのかを求める方法を解説します。
例えば、合計値が10の場合、これは8と2の和として表せます。8も2もフィボナッチ数であり、しかもフィボナッチ数列の中で隣り合っていません。この性質はゼッケンドルフの定理として知られており、「任意の正の整数は、連続しないフィボナッチ数の和として必ず一意に表せる」ことを示しています。
それでは、考え方をつかむためのアルゴリズムを見ていきましょう。
アルゴリズム
nonNeighbourFibo(sum)
Begin
while sum > 0, do
fibo := sum 以下で最大のフィボナッチ数
print fibo
sum := sum - fibo
done
End
処理の流れ
このアルゴリズムは貪欲法に基づいています。合計値が0より大きい間、次の手順を繰り返します。
- 残りの合計値以下で最大のフィボナッチ数を求める
- そのフィボナッチ数を出力する
- 合計値からそのフィボナッチ数を引く
毎回「残りの値を超えない最大のフィボナッチ数」を選ぶため、次に選ばれる数は必ず2つ以上前の項になります。これにより、選ばれたフィボナッチ数同士が数列の中で隣り合わないことが自動的に保証されます。
C++での実装例
#include<iostream>
using namespace std;
int fibonacci(int n) {
if (n == 0 || n == 1)
return n;
// n 以下で最大のフィボナッチ数を取得する
int prev = 0, curr = 1, next = 1;
while (next <= n) {
prev = curr;
curr = next;
next = prev + curr;
}
return curr;
}
void nonNeighbourFibo(int sum) {
while (sum > 0) {
int fibo = fibonacci(sum);
cout << fibo << " ";
sum = sum - fibo;
}
}
int main() {
int sum = 120;
cout << "Sum is same as Non-adjacent Fibonacci terms: ";
nonNeighbourFibo(sum);
}
コードのポイント
- fibonacci(int n): 3つの変数 prev・curr・next を順に更新しながらループを回し、n 以下で最大のフィボナッチ数を返します。
- nonNeighbourFibo(int sum): 合計値が0になるまで、「残りの値以下で最大のフィボナッチ数」を出力しては差し引いていくことで、非隣接フィボナッチ数の組み合わせを求めます。
出力結果
Sum is same as Non-adjacent Fibonacci terms: 89 21 8 2
この出力から、120 = 89 + 21 + 8 + 2 であることが分かります。89・21・8・2はすべてフィボナッチ数であり、数列の中で互いに隣り合っていないことも確認できます。
-
C++で学ぶクイックソート(QuickSort)の仕組みと実装方法
クイックソートとはクイックソート(Quicksort)は、比較に基づいて未ソートのリスト(配列)を並べ替えるソートアルゴリズムの一つです。「パーティション交換ソート(partition exchange sort)」とも呼ばれます。クイックソートは安定ソートではありません。これは、等しい値を持つ要素同士の相対的な順序が保持されないためです。ただし、配列に対してごくわずかな追加メモリだけで動作するため、メモリ効率に優れています。選択ソートと非常に似ていますが、常に最悪のパーティションを選んでしまうわけではない点が異なり、より洗練された形の選択ソートと捉えることもできます。クイックソートは最も効率
-
最初のn個の自然数の二乗和を求めるC++プログラムの解説
はじめにこの記事では、最初のn個の自然数(1からnまで)の二乗和を求める方法について解説します。例えば、n = 4 の場合、計算結果は 1² + 2² + 3² + 4² = 1 + 4 + 9 + 16 = 30 となります。基本的なアプローチとしては、1からnまで繰り返すforループを使用し、各ステップで項の二乗を計算して合計に加算していく方法があります。このプログラムの計算量は O(n) です。しかし、O(1) の定数時間で解きたい場合は、次の級数の公式を利用できます。Σk² = n(n + 1)(2n + 1) / 6この公式を使えば、ループ処理を行わずに一発で答えを求めることが可能で