关于四则运算表达式计数问题的讨论

关于四则运算表达式计数问题的讨论

前几天 @王赟 Maigo 大大发布了系列文章“如何不重复地枚举 24 点算式?”

王赟 Maigo:10897 如何不重复地枚举 24 点算式?(上)zhuanlan.zhihu.com图标王赟 Maigo:10897 如何不重复地枚举 24 点算式?(中)zhuanlan.zhihu.com图标王赟 Maigo:10897 如何不重复地枚举 24 点算式?(下)zhuanlan.zhihu.com图标

其中讨论了如何枚举使用加、减、乘、除组成的不等价的算式,所以枚举算式的问题已经解决了,接着就该讨论相关的计数问题了。下面这两个回答( @小于0@王赟 Maigo )里已经提到了一些结果和相关的 OEIS 数列

N个数,用+-×÷()连接,可以构成多少个算式?www.zhihu.com图标N个数,用+-×÷()连接,可以构成多少个算式?www.zhihu.com图标

本文尝试着求一下四则运算表达式计数问题对应数列的生成函数。


涉及到的几个 OEIS 数列

A006351:n 个变量的使用加法、乘法组成的不等价的算式个数。我们用 r_n 表示该数列,用 R(z) 表示其指数生成函数。

A140606:n 个变量的使用加、减、乘、除组成的不等价的算式个数。我们用 s_n 表示该数列,用 S(z) 表示其指数生成函数。

A182173:n 个变量的使用加、减、乘、除(允许使用单目负号运算)组成的不等价的算式个数。我们用 t_n 表示该数列,用 T(z) 表示其指数生成函数。

A247982:n 个变量的使用加、减、乘、除组成的不等价的算式个数(互为相反数的算式被认为是等价的,所以该数列应该等于 A182173 的二分之一)。

另外我们再定义一个数列: n 个变量的使用加、乘、除组成的不等价的算式个数,我们用 u_n 表示该数列,用 U(z) 表示其指数生成函数。

在 OEIS 上关于 A006351 有较多的结论和参考材料,然而对于另外几个数列相关的内容就比较少了。现在我们的主要目标是求 S(z) ,我们从相对简单的 R(z) 开始,尝试着求出生成函数所满足的方程(组)。然后用同样的方法处理 U(z) 和 T(z),最后我们讨论 S(z) 与 U(z) 和 T(z) 之间的关系。这里我们求解生成函数主要使用的是解析组合(Analytic Combinatorics)的 Symbolic method 方法。


求解 R(z)(使用加法、乘法组成的不等价的算式个数)

我们的主要思路是先将算式分为两类,一类是“加性的”,一类是“乘性的”,加性指的是算式最外层的运算符为 + 或 -,比如 a/b+c;乘性指的是最外层的运算符为 * 或 /,比如 a/b/(c-d),然后分别定义这两类算式对应的组合类 R+ 和 R*。注意到若干个乘性算式加起来(不考虑顺序)能够构成一个加性算式,而若干个加性算式乘起来(不考虑顺序)能够构成一个乘性算式,所以我们可以得到组合类表述

\left\{\begin{matrix} \mathcal{R}_+= \mathcal{Z} + \text{SET}_{\geq 2} (\mathcal{R}_*) \\ \mathcal{R}_* = \mathcal{Z} + \text{SET}_{\geq 2} (\mathcal{R}_+) \end{matrix}\right.

其中,Z 对应单个变量的算式,SET(R) 对应由两个及以上的加性(乘性)算式乘(加)起来构成的新算式。然后利用 symbolic method 将组合类表述转换为对应生成函数的方程组

\left\{\begin{matrix} R_+ (z) = z + \sum_{k \geq 2} \left[ R_* (z) \right] ^ k / k! = z + e^{R_* (z)} -1 - R_* (z) \\ R_* (z) = z + \sum_{k \geq 2} \left[ R_+ (z) \right] ^ k / k! = z + e^{R_+ (z)} -1 - R_+ (z) \end{matrix}\right.

接着,考虑到加性和乘性算式合起来不就是所有用加法、乘法组成的算式嘛,其中需要去掉一个重复的单变量的算式,所以我们有

 R(z) = R_+ (z) + R_* (z) - z

这里提醒一下 R+(z) 和 R*(z) 其实是相等的,它们对应的数列是 A000311 。所以当 n>=2 时, A006351 是 A000311 的 2 倍。另外,关于 A000311 的生成函数的求解可以参考 Analytic Combinatorics 的第 128 页,见下图

按照 R(z) 的方程组我们可以递推地求出每项的系数,当然了计算的效率会比较低。我用 Sagemath 求了一下前几项(n 再大就比较费时了),比对 OEIS 数列是相符的


求解 U(z)(使用加、乘、除组成的不等价的算式个数)

类似地,我们将算式分为加性和乘性两类。考虑到若干个乘性算式加起来能够构成一个加性算式;而若干个加性算式乘起来能够构成一个乘性算式(每个子算式可以取它本身或者取它的倒数,但是不能全取倒数,比如 \frac{1}{a} \cdot b \cdot \frac{1}{c + d} 是一个算式,而 \frac{1}{a} \cdot \frac{1}{b} \cdot \frac{1}{c + d} 就不是了)。所以可以得到组合类表述

\left\{\begin{matrix} \mathcal{U}_+= \mathcal{Z} + \text{SET}_{\geq 2} (\mathcal{U}_*) \\ \mathcal{U}_* = \mathcal{Z} + (2^2-1) \cdot \text{SET}_{= 2} (\mathcal{U}_+ ) + (2^3-1) \cdot \text{SET}_{= 3} (\mathcal{U}_+ ) + \cdots \end{matrix}\right.

其中第一个方程和上一节类似,第二个方程中 \text{SET}_{= k} (\mathcal{U}_+ ) 对应于 k 个子算式乘起来构成的新算式,2^k - 1 是因为 k 个子算式都可以取它本身或者倒数,但不能全取倒数。然后应用 symbolic method 得到对应的生成函数的方程组

\begin{aligned} U_{+}(z) &= z + \sum _{k \geq 2} \frac{1}{k!} \left[ U_*(z) \right] ^k \\ &=z + \left[ e ^{U_*(z)} -1 - U_*(z)\right] \end{aligned}

\begin{aligned} U_*(z) &= z + \sum _{k \geq 2} \frac{ 2^k - 1}{k!} \left[ U_+(z) \right] ^k \\ &=z + \left[ e ^{2U_+(z)} -1 - 2U_+(z) \right] - \left[ e ^{U_+(z)} -1 - U_+(z) \right] \\ &= z + e ^{2U_+(z)} - e ^{U_+(z)} - U_+(z) \end{aligned}

类似的,加性和乘性算式合起来再去掉重复就是所有算式,所以

U(z) = U_+(z) + U_*(z) - z

另外,这个数量等于 @王赟 Maigo 文章中提到的“无极性”的算式个数, @小于0@王赟 Maigo 都说明了 算式“有极性”等价于算式中有 - 运算符

用 Sagemath 计算得到的前几项的值


求解 T(z)(允许单目负号运算的用加、减、乘、除组成的不等价的算式个数)

类似地,我们将算式分为加性和乘性。考虑到若干个乘性算式加起来能够构成一个加性算式;而若干个不考虑负号的加性算式乘起来能够构成一个乘性算式,然后每个构成后的算式还可以是正的和负的。所以可以得到组合类表述

\left\{\begin{matrix} \mathcal{T}_+= 2\mathcal{Z} + \text{SET}_{\geq 2} (\mathcal{T}_*) \\ \mathcal{T}_* = 2\mathcal{Z} + 2\left [ (2^2-1) \cdot \text{SET}_{= 2} (\mathcal{T}_+ / 2) + (2^3-1) \cdot \text{SET}_{= 3} (\mathcal{T}_+ /2) + \cdots \right ] \end{matrix}\right.

其中 2Z 表示单个变量的算式 a 和 -a; \mathcal{T}_+ /2 对应于不考虑负号的算式(互为相反数的算式被认为是等价的)组合类;同样地,每个子算式可以取它本身或者它的倒数说明数量需要乘以 2^k,再减去一个所有都取倒数的情况,方括号外面的一个 2 是因为每个构成后的算式可以是正的和负的。

应用 symbolic method 得到对应生成函数的方程组

\begin{aligned} T_{+}(z) &= 2z + \sum _{k \geq 2} \frac{1}{k!} \left[ T_*(z) \right] ^k \\ &= 2z + \left[ e ^{T_*(z)} -1 - T_*(z)\right] \end{aligned}

\begin{aligned} T_*(z) &= 2z + 2 \sum _{k \geq 2} \frac{2^k-1}{k!} \left( \frac {T_+(z)}{2} \right) ^k \\ &= 2z + 2\left[ e ^{T_+(z)} -1 - T_+(z) \right] - 2\left[ e ^{T_+(z) / 2} -1 - \frac{1}{2} T_+(z) \right] \\ &= 2z + 2 e ^{T_+(z)} - 2 e ^{T_+(z) / 2} - T_+(z) \end{aligned}

T(z) = T_+(z) + T_*(z) - 2z

用 Sagemath 求前几项的值,比对 OEIS 数列是相符的


求解 S(z)(使用加、减、乘、除组成的不等价的算式个数)

最后,考虑到允许单目负号运算的算式中去掉负性算式(负性算式指算式最外层运算符为单目负运算,比如 -a/b-c 和 -(a+b)*c-d 都是负性算式,这些算式的最外层运算符无法消去)就是所有合法的不等价算式,而对负性算式再取负后就是无极性”的算式了(可以参考 @小于0 的回答)!所以允许单目负号运算的算式数量减去“无极性”的算式数量就是不等价的算式数量,因此有

S(z) = T(z) - U(z)


总结

我们利用 Symbolic method 求解了一下几个四则运算表达式计数问题中的指数生成函数所满足的方程组。根据方程组,我们可以得到数列的递推计算方法,但是递推计算的复杂度比较高,我们只验证了 n 比较小的情况。感谢 @酱紫君 大大用软件验证了前 100 项,而且算的还特别快,所以我们得到的这些方程(组)应该是对的。


感谢

这里要特别感谢 @王赟 Maigo 大大在预览本文时提出的宝贵建议。


更新:生成函数有了之后我们接着就可以考虑渐进近似的问题了,在下一篇文章中我们试着求解了一下这些数列的渐进近似

终军弱冠:关于四则运算表达式数量的渐进近似zhuanlan.zhihu.com图标




2018.3.1

2018.3.25 更新

编辑于 2018-03-25