引例:
洛谷P1225
题目描述
楼梯有N阶,上楼可以一步上一阶,也可以一步上二阶。
编一个程序,计算共有多少种不同的走法。
输入输出格式
输入格式:
一个数字,楼梯数。
输出格式:
走的方式几种。
看到这个题,首先想到的是用递归,那么我们对于上最后一节台阶的方法数进行一下书写的话,会发现
可以迈一步上去,也可以迈两步上去,那么就有了f(n)=f(n-1)+f(n-2);
这个其实还是比较好想的,仔细研究后发现,这一递推式刚好能够满足所有子问题,然后对一阶台阶和两阶台阶进行一下计算,这个题就OK了。
233333这是什么大水题
but。。。。。。。。。。。
很恶心的事情出现了,由于答案太大,而该死的luogu又不让对大质数取模。。。。
即使是用long long也只能拿一半得分的情况下,只有高精能行了,代码实现如下
思路大概是用数组f[k][j]来存储走k个阶梯所用的步数 最后循环输出
#include
#include
#include
#include
#include
using namespace std;
int n,len=1,f[5003][5003];
void lt(int k)//高精度加法,k来存阶数
{
int i;//其实写递归和递推,主要用的是循环操作,可以函数内嵌来循环,好处是好想而且代码简介,但是不好的地方是对于一些取模等操作,有些麻烦,
所以我们使用循环的方法来解决
for(i=1;i<=len;i++)
f[k][i]=f[k-1][i]+f[k-2][i];
for(i=1;i<=len;i++)
if(f[k][i]>=10)//进位
{
f[k][i+1]+=f[k][i]/10;
f[k][i]=f[k][i]%10;
if(f[k][len+1])len++;
}
}
int main()
{
int i;
cin>>n;
f[1][1]=1; f[2][1]=2; //特判一下1,2
for(i=3;i<=n;i++) //从3开始的话,避免越界
lt(i);
for(i=len;i>=1;i--)
cout<<f[n][i];//最后逆序输出
return 0;
}
好了,这个题解决完了,那么我们看一下它的升级版。。。。。。。虽然都是橙题。。。。。。
P1192 台阶问题
题目描述
有NN级的台阶,你一开始在底部,每次可以向上迈最多KK级台阶(最少11级),问到达第NN级台阶有多少种不同方式。
输入输出格式
输入格式:
两个正整数N,K。
输出格式:
一个正整数,为不同方式数,由于答案可能很大,你需要输出ans mod100003后的结果。
这。。。。。。人类福音啊喂
这个题的话,可以照搬上一题的思想,但是这里的最多迈两阶变成了最多迈k阶
这样的话,我们就可以用一套循环来解决,这个是中心部分
for(int i=1;i<=n;++i) { for(int j=1;j<=k&&i-j>=0;++j) qaq[i]+=qaq[i-j]; qaq[i]%=100003; }
很容易看到,由外循环i控制第几节台阶的方案数,内循环j控制迈几步
内循环完事之后取模一次,然后重复。。。。。
AC代码如下
#include#include #include #include #include using namespace std; int n,k,qaq[100001]={1}; int main() { cin>>n>>k; for(int i=1;i<=n;++i) { for(int j=1;j<=k&&i-j>=0;++j) qaq[i]+=qaq[i-j]; qaq[i]%=100003; } cout<<qaq[n]; return 0; }
这个题还有一点,是判断一下当前的台阶总数是不是比最多迈的台阶数大,也就是i-j>=0;
这里进行一下特判就OK啦。
个人想法,
递归和递推都是把复杂问题简单化,通过若干个子问题来解决父问题(让儿子干死他爹), 解这类题的关键就是找到一个公式能够持续循环下去,其实我觉得在学习了数学归纳法和数论的相关内容之后,对于递归和递推的理解会更好一点。