上台阶
- 现在小瓜想通过台阶走上平台,最底层(小瓜所在的层)编号为1,最顶层编号为n。由于小瓜的腿比较短,他一次只能向上走1级或者2级台阶。小瓜想知道他有多少种方法走上平台,你能帮帮他吗?
输入
一个整数n,其中2≤n≤25。
输出
一行一个整数,表示小瓜上台阶的方案数
数据范围
对于12%的数据,2≤n≤5;
对于28%的数据,2≤n≤10;
对于100%的数据,2≤n≤25;
输入样例
4
输出样例
3
样例解释
从台阶1到台阶4,可能方案有:
1→2→3→4,1→2→4,1→3→4,共3种。
这题我们首先想到的是递归。。。
//include<bits/stdc++.h>
#include <iostream>
#include<cstdio>
using namespace std;
int total;
int sum(int num,int n){
if(num>n){
return 0;
}
if(num==n){
total++;
return 0;
}
sum(num+1,n);
sum(num+2,n);
}
int main(){
int n;
cin>>n;
sum(1,n);
cout<<total;
return 0;
}
然后再思考除了递归,还有没有更高效的解决办法?
递归的毛病在于数据量一旦大了,就会发生时间超限的问题。
我们尝试一个档次高一点的方法,用在这里有点像斐波那契数列的赶脚。。。
//include<bits/stdc++.h>
#include <iostream>
using namespace std;
int f[55];
int main(){
f[1]=1,f[2]=1;
int n;
cin>>n;
for(int i=3;i<=n;i++){
f[i]=f[i-1]+f[i-2];
}
cout<<f[n];
return 0;
}
沉思一会,发现这不就那个DP吗???这就是那个传说中巨难的动态规划??!
一点没错,这就是最简单基础的动态规划。。。
- 小瓜想走上一个一共有n级的台阶,由于小瓜的腿长比较特殊,他一次只能向上走1级或者3级或者5级台阶。小瓜想知道他有多少种方法走上这n级台阶,你能帮帮他吗?
输入
一行一个整数n(n<=100000),表示一共有n级台阶。
输出
一行一个整数,表示小瓜上台阶的方案数对100003取余的结果。
输入样例
3
输出样例
2
这题因为数据量变大了,只能用动态规划,可以参照上面的那个简单的dp做修改。。。
//include<bits/stdc++.h>
#include <iostream>
using namespace std;
const int N=100005;
int dp[N];
int total;
const int mod=100003;
int main(){
int n;
cin>>n;
dp[0]=1,dp[1]=1,dp[2]=1;
for(int i=3;i<=n;i++){
if(n>=5){
dp[i]=(dp[i-1]+dp[i-3]+dp[i-5])%mod;
}else if(n>=3){
dp[i]=(dp[i-1]+dp[i-3])%mod;
}
}
cout<<dp[n];
return 0;
}
- 小瓜想走上一个一共有n级的台阶,由于小瓜的腿长比较特殊,他一次只能向上走1,4,7,10…(即3n+1)级台阶。小瓜想知道他有多少种方法走上这n级台阶,你能帮帮他吗?
输入
一行一个整数n(n<=100000),表示一共有n级台阶。
输出
一行一个整数,表示小瓜上台阶的方案数,结果对100003取余。
输入样例
5
输出样例
3
样例解释
对于样例,有3种走法:
1,1,1,1,1
1,4
4,1
这题如果按照递归的思想来做的话:
//include<bits/stdc++.h>
#include <iostream>
#include<cstdio>
using namespace std;
int total,j;
int sum(int num,int n){
if(num>n){
return 0;
}
if(num==n){
total++;
total%=100003;
return 0;
}
for(int i=0;i<=n;i++){
j=3*i+1;
sum(num+j,n);
}
}
int main(){
int n;
cin>>n;
sum(0,n);
cout<<total;
return 0;
}
虽然说思想上没什么错,但照题目所给的数据量来看,时间不够,会爆炸~
换成dp的思路重新分析一下:
同上台阶2的递推类似,假设我们有了 1−>(n−1) 的所有的答案,那么考虑到达位置 n 的最后一步可以跨 1,4,7,10… 级,对应从 n−1,n−4,n−7… 这些不同的位置直接到达 n ,且没有重复的方案,因此得到递推式为:
F(n)=F(n−1)+F(n−4)+F(n−7)+F(n−10)+…
这个算法的复杂度是 O(n2) 的。
我们对已有的递推式进行优化改进。
F(n)=F(n−1)+F(n−4)+F(n−7)+F(n−10)+…F(n−3)=F(n−4)+F(n−7)+F(n−10)+…
因此原来的递推式可以化简为:
F(n)=F(n−1)+F(n−3)
这个递推式的计算复杂度是 O(n) 的。
//include<bits/stdc++.h>
#include <iostream>
using namespace std;
const int N=100005;
int dp[N];
int total;
const int mod=100003;
int main(){
int n;
cin>>n;
dp[0]=1,dp[1]=1,dp[2]=1;
for(int i=3;i<=n;i++){
dp[i]=(dp[i-1]+dp[i-3])%mod;
}
cout<<dp[n-1];
return 0;
}
ps:至于这里的输出dp[n-1]而不是dp[n],是由于根据给出的样例分析得到的情况而做出的调整,或者根据递推式来得出的结论,总之动态规划还是一种比较玄的方法~