题目链接: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 }
完。