【POJ】2019计算机学科夏令营上机考试 D:上楼梯

【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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值