洛谷P1192 台阶问题

题目描述

有N级的台阶,你一开始在底部,每次可以向上迈最多K级台阶(最少1级),问到达第N级台阶有多少种不同方式。


输入格式

两个正整数N,K。


输出格式

一个正整数,为不同方式数,由于答案可能很大,你需要输出ans mod 100003后的结果。


说明

对于20%的数据,有N ≤ 100,
对于100%的数据,有N ≤ 100000

原题链接

链接: https://www.luogu.com.cn/problem/P1192

解题思路

假设一个台阶有4级,每次最多走3级。
如果第一步走1级,则剩下的走法和从0级到3级的走法是一样的。
如果第一步走2级,则剩下的走法和从0级到2级的走法是一样的。
如果第一步走3级,则剩下的走法和从0级到1级的走法是一样的。


way[n]为从第0级走到第n级台阶方法数
每次最多能上k级。
当第一步走1级,走到第n级的方法和走到n-1级的方法相同。
当第一步走2级,走到第n级的方法和走到n-2级的方法相同。

当第一步走k级,走到第n级的方法和走到n-k级的方法相同。


走到n级的所有方法就被分为了第一步走1级,2级…k级一共k种,走到n级的方法就等于先分别走1,2,3…k级的所有方法求和。


于是我们得到了下面的递推式
way[n]=way[n-1]+way[n-2]+…+way[n-k]
有了这个递推式后,我们只需求出way[1]——way[k],way[k+1]——way[n]都可由递推式获得。


核心代码

//先将way[]初始化为0;
for (int i = 1; i <= n; i++)			//遍历递推
	{
		for (int m = 1; m <= k; m++)   //阶数最少1到最大k阶依次累加
		{		
			if (i >= m)      //目标是i级,要走的步数不能比i大。
			{
				way[i] = way[i] + way[i - m];	
				way[i] = way[i] % 100003;  //每次循环都作取模运算,防止数字太大数组溢出
			}
		}
	}

完整代码:

#include<iostream>
using namespace std;

int main() {
	int n, k;
	int way[100010] = { 0 };
	way[0] = 1;		//起点到起点是1种方法。
	cin >> n >> k;
	for (int i = 1; i <= n; i++)			
	{
		for (int m = 1; m <= k; m++)   
		{
			if (i >= m)     
			{
				way[i] = way[i] + way[i - m];	
				way[i] = way[i] % 100003;
			}
		}
	}

	cout << way[n];
	return 0;

}

心得体会

做半天,我好菜
这个问题用递归也可以解决,但是数据量太大递归必定爆栈。所以使用递推会是一个比较好的解法。但是此题最大台阶数有105个。在解此题时创建了way[100000]大小的数组,使用的空间较大。按照递推式来看,只要求出了way[1]——way[k]之后,way[k+1]——way[n]都可以使用之前的的数据进行求解。并且根据递推式,也只需要k+1大小的数组即可,way[n]可以由way[n-1],way[n-2]…way[n-k]一共k个数据求和得到,而way[n-k]可由way[n-k-1]——way[n-k-k]k个数据求得,我们只需要保存最近的k个数据就可以了。再额外留出一个数据存放最后要求那个数据即可。可用队列实现,最小值参与计算后出队,计算求得值入队,可以进一步节省空间。

部分思路借鉴:
链接:https://www.luogu.com.cn/problem/P1192

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值