递归经典问题
题目描述
从楼上走到楼下共有h个台阶,每一步有3种走法:走一个台阶;走两个台阶;走三个台阶。规定只能往下走,不能往上走。
调皮的小明在n个台阶上撒了水,为了防止滑倒,不能踏上这n个台阶,问从楼上到楼下可走出多少种方案?
输入描述
第一行两个数字h, n,分别表示总台阶数和不能走的台阶数 (1 <= n < h <= 15)
接下来n行,每行一个整数a_i,表示第a_i级台阶被撒了水不能走
输出描述
一个整数,表示从楼上到楼下的方案数。
样例输入
5 1
3
样例输出
5
代码:
#include <iostream>
#include <memory.h>
using namespace std;
//递归法求下楼梯问题
//int now = 0; //当前在第now阶,可视为走过的台阶数
int Count = 0; //方案总数
void stair(bool* arr, int h, int sum) {
//递归终结点:
if (h == 0) {
Count++;
return;
}
if (h >= 1 && arr[sum - h]) {
stair(arr, h - 1, sum);
}
if (h >= 2 && arr[sum - h + 1]) {
stair(arr, h - 2, sum);
}
if (h >= 3 && arr[sum - h + 2]) {
stair(arr, h - 3, sum);
}
}
int main() {
int h, n; //h:总台阶数,n:不嫩走的台阶数
cin >> h >> n;
bool walk[16];
memset(walk, true, 16);
for (int i = 0; i < h; i++)
walk[i] = true;
// bool ah = false;
for (int i = 0; i < n; i++) {
int a_i;
cin >> a_i;
walk[a_i - 1] = false;
// if (a_i == h)
// ah = true;
}
//if (ah)
// h++;
int now = 0; //当前已下第n阶
stair(walk, h, h);
cout << Count << endl;
return 0;
}
注:
- 当n=3时只可能第1阶和第2阶有水,故不可能发生a_i == h的情况
- 在递归时由于每次将一个大问题化简为一个小问题,每次调用时“虚拟”的剩余台每次都会变,因此需要传入一个不变量表示当前位于那一段台阶。
如有不足欢迎大家在评论区指正。
——————————————————分割线————————————————————
三年后再回来看看发现自己写的是一坨xx ,就是普通的暴搜,附上翻新版代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 20;
int st[N]; //当前的楼梯能不能走,不能走位true
int res = 0;
int n, h;
void dfs(int u) {
if(u == 0) {
res ++;
return ;
}
if(u < 0) return ;
if(st[u]) return ; //某个楼梯有水,跳过
dfs(u - 1);
dfs(u - 2);
dfs(u - 3);
}
int main() {
scanf("%d%d", &h, &n);
for(int i = 0; i < n; i ++) {
int x;
scanf("%d", &x);
st[x] = true;
}
dfs(h);
cout << res << endl;
return 0;
}