【POJ】2019计算机学科夏令营上机考试 D:上楼梯
题目描述
小S在玩一个叫上楼梯的游戏。楼梯一共有n层台阶。
因为腿长的限制,小S每次最多只能上k层台阶。
小S是一个迷信的人,所以他不希望自己某一步走的步数的数字里有"4",(比如4,14,44都含有数字"4")。
现在,小S想要知道,有多少种走完这n层台阶的方案?
输入描述
输入包含多组数据。
每组数据第一行输入一个整数 n, k(1 <= k <= n <= 50)。
输入以 n,k=0 结束。
输出
对于每组数据,输出一行一个整数,表示答案。
样例输入
10 1
10 2
18 8
0 0
样例输出
1
89
71262
提示
注意答案可能超过 int 所能表示的范围,请谨慎选择存储答案以及中间数据的数据类型。题解
阅读题目可以容易知道这是一道考察动态规划算法的题目,但和普通的爬楼梯题目不一样,这是一道附条件的动态规划算法:所附条件就是小明不会走出含有“4”的步幅。也就是说对于1≤k≤50这样一个数据量,如下步幅情形不应该出现: $$ \mathcal{K}:k\%10==4||k/4==10 $$ 所以根据所附条件K容易写出一下状态转移方程: $$ step(n)= \left\{ \begin{array}{l} 0&&if&n=0\\ \sum\limits_{i=1}^{k}step(n-k)&k\notin\mathcal{K}&if&n≥1 \end{array} \right. $$通过以上分析,下面给出C++源代码,希望其中的注释能够帮助你理解:
//题目连接:http://bailian.openjudge.cn/xly2019/D/
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
ll scheme(int n, int k) { //计算总的上楼梯方案
vector<ll>step(n + 1, 0);
if (n == 0 || n == 1) //边界情况:如果只有0或1级台阶
return n;
step[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k && j <= i; j++) { //必须要检查步幅和当前台阶数的大小
if (j % 10 == 4|| j / 10 == 4) //由于1≤k≤50所以这样足以涵盖含有“4”的步幅
continue;
else {
step[i] += step[i - j]; //状态转移方程:step[n] = step[n-1] + step[n-2] +...+ step[n-k]
}
}
}
return step[n];
}
int main() {
int N, K, g = 0; //N是楼梯台阶数,K是最大能上的台阶数,g是输入数据的组数
vector<vector<int>>arr(100,vector<int>(2)); //用于存储每一组输入数据
while (cin >> N >> K && N && K) {
arr[g][0] = N;
arr[g][1] = K;
g++; //记录输入有效数据的组数
}
if (g == 0) { //边界情况:如果输入无效则结束程序
cout << 0 << endl;
return 0;
}
int index;
for (index = 0; index < g; index++) {
cout << scheme(arr[index][0], arr[index][1]) << endl;
}
return 0;
}