C++でオイラー数を求める:再帰による実装と解説
オイラー数とは
数学においてオイラー数(Eulerian number)は、特殊な組合せ数の一種です。1からnまでの数を並べた順列のうち、「隣接する2つの要素を比較したとき、前の要素より後の要素が大きくなる箇所(昇順)がちょうどm個ある」ような順列の個数を表します。
オイラー数は一般に A(n, m) と表記されます。
問題の定義
この問題では、2つの整数 n と m が与えられます。求めたいのは、条件を満たす順列の個数、すなわちオイラー数 A(n, m) の値です。
例で問題を理解しよう
入力: n = 4、m = 2
出力: 11
解説:
1から4までの数の順列は、全部で以下の24通りあります。
1 2 3 4 1 2 4 3 1 3 2 4 1 3 4 2 1 4 2 3 1 4 3 2
2 1 3 4 2 1 4 3 2 3 1 4 2 3 4 1 2 4 1 3 2 4 3 1
3 1 2 4 3 1 4 2 3 2 1 4 3 2 4 1 3 4 1 2 3 4 2 1
4 1 2 3 4 1 3 2 4 2 1 3 4 2 3 1 4 3 1 2 4 3 2 1
これらのうち、昇順がちょうどm(= 2)個になる順列は11個存在します。
解法のアプローチ
順列をすべて列挙して数える代わりに、オイラー数には以下の漸化式が成り立つことを利用します。
A(n, m) = 0 (m ≥ n または n = 0 のとき)
A(n, m) = 1 (m = 0 のとき)
A(n, m) = (n − m) × A(n−1, m−1) + (m + 1) × A(n−1, m) (上記以外のとき)
この漸化式をそのまま再帰関数として実装すれば、すべての順列を列挙することなくオイラー数を求めることができます。
解法の実装例(C++)
サンプルコード
#include <iostream>
using namespace std;
int countEulerianNumber(int n, int m)
{
if (m >= n || n == 0)
return 0;
if (m == 0)
return 1;
return (((n - m) * countEulerianNumber(n - 1, m - 1)) + ((m + 1) * countEulerianNumber(n - 1, m)));
}
int main() {
int n = 5, m = 3;
cout << "オイラー順列の個数は " << countEulerianNumber(n, m) << " です";
return 0;
}
実行結果
オイラー順列の個数は 26 です
まとめ
オイラー数 A(n, m) は、昇順の個数によって順列を分類する重要な組合せ数です。漸化式を用いた再帰実装により、効率よく答えを求められます。ただし、素朴な再帰は同じ計算を繰り返すため、n が大きい場合はメモ化(動的計画法)を組み合わせると、さらに計算量を抑えることができます。
-
C++で質素数(Frugal Number)を判定する方法【サンプルコード付き】
この記事では、正の整数 N が与えられたときに、その数が質素数(Frugal Number)であるかどうかを判定するプログラムを C++ で作成する方法を解説します。 質素数とは? 質素数(FRUGAL NUMBER)とは、その数自身の桁数が、素因数分解による表現の桁数よりも厳密に大きい数のことです。 例:625 の場合 625 を素因数分解すると 54 となります。 625 自身の桁数:3 桁 54 の表現の桁数:2 桁 3 は 2 よりも厳密に大きいため、625 は質素数です。 最初のいくつかの質素数:125、128、243、256、343、512、625 など 問題を理解するための具
-
C++で五胞体数(ペンタトープ数)を求める方法
五胞体数とは? 五胞体数(ペンタトープ数)は、パスカルの三角形の第5の対角線上に現れる数列として知られています。この数列を定義するには、パスカルの三角形に少なくとも5つの数が必要となるため、数列の最初の数はパスカルの三角形の第4行である 1 4 6 4 1 から始まります。 本チュートリアルでは、n番目の五胞体数を求める方法を解説します。まずは具体的な例を見てみましょう。 入力 : 1出力 : 1入力 : 4出力 : 35 以下の図から出力を確認できます。 この問題は数列に関するものなので、解法ではまず数列のパターンを見つけることから始めます。 解法のアプローチ このプログラムでは、数列の