洛谷P1192台阶问题(逆向递推递归dfs+记忆化)

题目链接:https://www.luogu.org/problemnew/show/P1192

 

题目很有价值,用搜索写的话,可以加深对递归搜索的理解。

一般这样的递推题规律题可以用:dp或记忆化(我就用记忆化了

所以啊,用正向递归还是逆向递归,关键看题目有没有规律,递推性!(数据范围,题目求的是否就是要暴力所有情况)

 

刚开始,直接正向单向递归dfs,最暴力的原始走,把所有方法都试一遍,走到尾位置,过了一个点超时四个。。

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <iomanip>
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <cmath>
 8 using namespace std;
 9 typedef long long ll;
10 typedef unsigned long long ull;
11 const int maxn=1e6+5;
12 const int mod=100003;
13 int a[maxn];
14 int n,k;
15 int ans;
16 
17 void so(int sum,int step)//sum代表已经走的级数,step代表走了几步为了方便输出观察正确方案(可以不要对题目没影响)
18 {
19     if(sum==n)
20     {
21         ans++;
22         //for(int i=0;i<=step-1;i++) cout<<a[i]<<' ';//排列输出,方便观察是否正确
23         //cout<<endl;
24         return;
25     }
26 
27     for(int i=1;i<=k;i++)
28     {
29         if(sum+i>n) break;
30         //a[step]=i;//排列输出,方便观察是否正确
31         so(sum+i,step+1);
32     }
33 }
34 
35 
36 int main()
37 {
38     ios::sync_with_stdio(false); cin.tie(0);
39 
40     ans=0;
41     so(0,0);
42 
43     cout<<ans<<endl;
44 
45     return 0;
46 }

 

之后又想能不能记忆化保存起来,但好像没办法啊,看了大佬题解后,果然是我太菜。。。

这是规律题,可以找规律啊,逆向递归dfs然后保存起来啊,逆向递归很容易保存记忆化。(一般正向不行就试试逆向会有惊喜!)

 1 #include <iostream>
 2 #include <string>
 3 #include <algorithm>
 4 #include <iomanip>
 5 #include <cstdio>
 6 #include <cstring>
 7 #include <cmath>
 8 using namespace std;
 9 typedef long long ll;
10 typedef unsigned long long ull;
11 const int maxn=1e6+5;
12 const int mod=100003;
13 int a[maxn];
14 int jilu[maxn];
15 int n,k;
16 //int ans;
17 
18 int so(int sum)//sum代表剩余的级数
19 {
20     if(jilu[sum]) return jilu[sum];
21     //if(sum==0) return 1;//可改写1:有了记忆化开始保存,这句话在这基本么什么用(没记忆化时才有用递归出口)
22 
23     int ans=0;
24     for(int i=1;i<=k;i++)
25     {
26         //if(sum-i<0) break;//可改写2:因为从小到大来的,一个<,后面更大一定<,所以可直接退出不用再判断了(可以代替sum-i>0)
27         if(sum-i>=0)
28         {
29             ans=(ans+so(sum-i))%mod;//这一层的方案数=走了一层方案数+下下一层+...+走下k层方案数
30         }                           //以3或1为例跟一遍就明白!
31     }
32     jilu[sum]=ans;
33     return ans;
34 }
35 
36 
37 int main()
38 {
39     ios::sync_with_stdio(false); cin.tie(0);
40 
41     cin>>n>>k;
42 
43     jilu[0]=1;//比如从1一步到0,从2一步到0,从k一步到0都是这1种走法
44     cout<<so(n)<<endl;
45 
46     return 0;
47 }

 

完。

 

posted @ 2018-10-19 11:07  RedBlack  阅读(413)  评论(0编辑  收藏  举报