4.2.2 Catalan数列
【问题】Catalan数列是欧拉在计算凸多边形的三角形剖分问题时得到的。在一个凸n(n>=3)边形中,通过插入内部不相交对角线将其剖分成一些三角形区域,问有多少种不同的分法?三角形只有一种剖分方法,图4-1所示是四边形的两种剖分,图4-2所示是五边形的5种剖分。Catalan数列的前5项是{1, 2, 5, 14, 42,...}
【想法】 由几何学知识,当n二4时,凸n边形的一个剖分需引n-3条互不相交的对角线,将内部区域剖分成n-2个三角形。凸n边形的顶点用A1, A2, …,An 表示,取边A1,An, 再取凸n边形的
任一个顶点Ak(2<=k<=n-1), 将Ak分别与A1和An连线得到三角形T,则三角形T将凸n边形分成R1、T和R2三个部分,其中R1为凸k边形,R2为凸n-k+1边形,如图4-3所示。
令h(n)表示凸n边形的三角形剖分方案数,则R1有h(k)种剖分方法,R2有h(n-k+1)种剖分方法。补充定义h(2)=1, 得到 Catalan 数列的递推关系式:
【算法实现】 设函数 Catalan 求解 Catalan 数列,设数组c[n+1]存储n个 Catalan 数列,补充赋值c[o]=c[1]=0,程序如下。
#include <iostream>
using namespace std;
int Catalan(int n) {
if (n <= 1) {
return 1;
} else {
int result = 0;
for (int i = 0; i < n; i++) {
result += Catalan(i) * Catalan(n - i - 1);
}
return result;
}
}
int main( )
{
int n;
std::cout << "请输入 Catalan 数列的索引:";
std::cin >> n;
int catalanNumber = Catalan(n);
std::cout << "索引 " << n << " 的 Catalan 数为:" << catalanNumber << std::endl;
return 0;
}
【算法分析】两数Catalan由两层嵌套循环构成,基本语句”temp +=c*[k]*c[i-k+1];"
的执行次数是
4.3.1 伯努利错装信封问题
【问题】欧洲数学家伯努利收到一位朋友的来信,打开一看信不是写给他的,但是信封上的地址、姓名都没有问题。过了几天,他收到这位朋友的道歉信,解释说:写了5封信,又写好了5个信封,然后让仆人把信寄出,可是那位仆人在把信装到信封里时居然全部都装错了!看完信后伯努利不禁哈哈大笑。不过他马上想到了一个问题:5 封信装入写有不同地址和姓名的5个信封,全部装错的可能性有多少种?
【想法】 伯努利错装信封问题又称错排问题(error permutation problem)。假设有n个信封,依次编号为1、2.…n,有n封信,也依次编号为1、2、….n,则编号i(1<=i<=n)的信只有装入编号i的信封才是正确的。设Fn表示n错排问题,有F1=0, F2=1。当n>2时,设第一封信装在第二个信封中,若第二封信装在第一个信封中,则剩下的即为n-2错排问题;若第二封信不装在第一个信封中,则剩下的即n-1错排问题,设第一封信不装在第一个信封中,共有n-1种方法,得到如下递推关系式:
【算法实现】 设函数 Bernoulli 实现错排问题,变量b1和b2分别存储n-1和n-2错排数,程序如下。
#include <iostream>
using namespace std;
/**
* 计算 Bernoulli 数的函数
*
* @param n 要计算的 Bernoulli 数的索引
* @return 索引为 n 的 Bernoulli 数
*/
int Bernoulli(int n)
{
int i, b, b1 = 1, b2 = 0;
for (i = 3; i <= n; i++)
{
b = (i - 1) * (b1 + b2); b2 = b1; b1 = b;
}
return b;
}
int main() {
int n;
cout << "请输入一个大于 2 的正整数:"; // 请求用户输入
cin >> n;
if (n < 3) { // 修改:添加错误处理
cout << "输入应为大于 2 的正整数" << endl;
return 1;
}
int bernoulliNumber = Bernoulli(n); // 计算并存储 Bernoulli 数
cout << "索引为 " << n << " 的 Bernoulli 数为:" << bernoulliNumber << endl; // 输出 Bernoulli 数
return 0;
}
【算法分析】 显然,算法Bernoulli的时间复杂度为O(n)。