注意
下文中的欧拉数特指 Eulerian number.注意与 Euler number,以及 Euler's number(指与欧拉相关的数学常数例如 或 )作区分.
在计算组合中,欧拉数(Eulerian Number)是从 到 中正好满足 个元素大于前一个元素(具有 个「上升」的排列)条件的排列 个数.定义为:
例如,从数字 到 一共有 种排列使得恰好有一个元素比前一个元素大:
| 排列 | 满足条件的相邻元素 | 个数 |
|---|---|---|
| 1 2 3 | 1, 2 & 2, 3 | 2 |
| 1 3 2 | 1, 3 | 1 |
| 2 1 3 | 1, 3 | 1 |
| 2 3 1 | 2, 3 | 1 |
| 3 1 2 | 1, 2 | 1 |
| 3 2 1 | 0 |
所以按照 定义:如果 等于 , 等于 ,欧拉数值为 ,表示共有 个有 个元素大于前一个元素的排列.
对于 和 值比较小的欧拉数来说,我们可以直接得到结果:
| 满足要求的排列 | 个数 | |
|---|---|---|
| 1 | ||
| 1 | ||
| 1 | ||
| 1 | ||
| 4 | ||
| 1 |
公式
可以通过递推或者递归的方法计算欧拉数.
首先,当 或 时,没有满足条件的排列,即此时欧拉数为 .
其次,当 时,只有降序的排列满足条件,即此时欧拉数为 .
最后,考虑在 的排列的基础上插入 从而得到 的排列,由于插入 至多使欧拉数增加 ,所以 可以仅从 处和 处转移得到.
考虑 插入的位置:当 时,若将 插到 之前,即将 插入到「上升」中,排列的欧拉数不变;此外,将 插在排列之前,排列的欧拉数也不变;否则,若将 插到其余位置,排列的欧拉数增加 .
考虑从 转移到 ,此时需要使欧拉数增加 ,此时不能将 插在「上升」中或者排列开头,共有 种方案.
考虑从 转移到 ,此时需要欧拉数保持不变,只能将 插在「上升」中或者排列开头,共 种方案.
综上所述,有
实现
C++
int eulerianNumber(int n, int m) {
if (m >= n || n == 0) return 0;
if (m == 0) return 1;
return (((n - m) * eulerianNumber(n - 1, m - 1)) +
((m + 1) * eulerianNumber(n - 1, m)));
}
Python
def eulerianNumber(n, m):
if m >= n or n == 0:
return 0
if m == 0:
return 1
return ((n - m) * eulerianNumber(n - 1, m - 1)) + (
(m + 1) * eulerianNumber(n - 1, m)
)