走楼梯:
楼梯有 N 阶,上楼可以一步上一阶,也可以一步上二阶。
编一个程序,计算共有多少种不同的走法。
递归:N阶段楼梯的走法 = (N-1)阶楼梯的走法+(N-2)阶楼梯的走法
算法理解:(N - 1)阶楼梯走法再走一阶楼梯到达第N阶,(N - 2)阶楼梯再直接走二阶楼梯到达第N阶(注意):(N - 2)阶楼梯再走两次一阶楼梯这种走法已经包含在了(N - 1)阶楼梯里,因此舍弃掉这种走法。
递归出口:
1、走到1阶楼梯时,剩余一种走法。
2、走到0阶楼梯时,定义为一种走法。(注意)这里需要结合实际情况讨论:当n = 2时,根据递归公式,2阶楼梯走法=1阶楼梯走法+0阶楼梯走法,(2 = 1 + 1)因此0阶楼梯需要定义为1种走法。
#include<iostream>
using namespace std;
int ladder;
int sum_Ladder(int ladder) {
if (ladder == 0) {
return 1;
}
if (ladder == 1) {
return 1;
}
return sum_Ladder(ladder - 1) + sum_Ladder(ladder - 2);
}
int main() {
cin >> ladder;
cout <<sum_Ladder(ladder);
}
斐波那契数列:
斐波那契数列:F(0)=0,F(1)=1, F(n)=F(n - 1)+F(n - 2)
例:0、1、1、2、3、5、8、13、21、34、.....
这种问题的答案符合斐波那契数列,因此也可以通过编写C++斐波那契数列解决问题。
#include<iostream>
using namespace std;
int ladder;
int main() {
long long a[501];
a[1] = 1;
a[2] = 2;
for (int i = 3; i < 501; i++) {
a[i] = a[i - 1] + a[i - 2];
}
cin >> ladder;//请输入小于500的数字
cout << a[ladder];
}
出栈序列有几种:
题目描述:
n 个元素进栈序列为:1,2,3,4,...,n,则有多少种出栈序列。
目标:求出有几种合法序列
思路:总序列减去非法序列
第一步:找到非法序列的条件
非法序列就是非法出栈。我们可以这样表示: 进栈代表1,出栈代表-1,当在某一个位置上的前缀和为负数时候,这一位置是非法的 → 这一序列也就是非法的。
例如:1,2,3的一个非法出栈序列为:+1, -1, -1, + 1, -1, +1。此时在第三个位置为-1,前缀和等于(+1) +(-1) +(-1)= -1 < 0。此时3号位置为第一个前缀和小于0的非法位置。
这样就找到了非法序列,所有的非法序列都满足这一规律。接下来第二步就是求出非法序列的个数。
第二步:求出非法序列的个数
首先我们要知道当有n个数时,所有的元素都要进栈和出栈,那么所有的出+1和-1个数加起来等于2n。
对于所有的非法序列,我们先在第一步的非法位置和它之前的所有位置都进行取反操作。(例如在第一步的三个元素的出栈序列中,找到的第三个位置前的元素都进行取反,这样这个序列就变成了4个+1和2个-1),由于整体序列为n个+1,n个-1,经过这样变换后,整个数列变成了(n+1)个+1和(n - 1)个-1的数列。 这里我们将原非法序列设为A,经过这种变换后的序列设为B,一个A只对应一个B(证明略,可以自己画图理解)。
因此我们想要知道因此非法序列A的总数,就只需要知道变种后的B序列的总数,由上一段可知,B的总数就是在2n个数里面选择(n+1)个数变为+1,B的总数为,相应的非法序列A的总数也就是,所有的出栈序列减去非法的出栈序列就等于合法的出栈序列: - =这就是卡特兰数的通项公式。
是不是忘记了之前学过的排列组合?
是排列,有顺序,表示m是起点,从m中按顺序取n个数
= m(m-1)(m-2)(m-3) ... (m-n+1)
例如: = 8x7x6x5
是组合,无顺序,表示从m中选出n个数
= (其中除以是把排列带来的顺序给去除掉)
例如: = =(8x7x6x5)/(4x3x2x1)
编程实现:
直接计算版本(不推荐):
#include<iostream>
using namespace std;
void Catalan(long long &num) {
long long C_up = 1;
int C_down = 1;
for (int i = num * 2; i > num; i--) {
C_up = C_up * i;
}
for (int i = num; i > 0; i--) {
C_down = C_down * i;
}
long long ans = C_up / C_down / (num + 1);
cout << ans;
}
int main() {
long long num;
cin >> num;
Catalan(num);
}
递推公式:
这个代码在数字量过大时将long long无法存储,可以采用高精度算法(偷懒一下,有时间再写),或递推公式。
下面采用递推公式:
推导:
递推代码:
#include<iostream>
using namespace std;
long long ctl[33];
void Catalan() {
ctl[0] = 1;
ctl[1] = 1;
for (int i = 1; i < 32; i++) {
ctl[i + 1] = ctl[i] * (4 * i + 2) / (i + 2);
}
}
int main() {
long long num;
cin >> num;
Catalan();
cout << ctl[num];
}