记忆化搜索
今天的时间较短,没有刷很多的题,只刷了一道记忆化搜索的题目,还调试了半天(就是因为输出没有换行TwT)。但就是这道题让我把新手村A掉啦~\(≧▽≦)/~
记忆化搜索
·记忆化搜索是啥?
所谓记忆化搜索,就是让程序实现自动记忆已经搜索过的东西,这样如果再次搜到这个东西,就可以直接调用了。
·记忆化搜索与dp的不同点:
dp需要对每个状态进行遍历,而记忆化搜索则可以排除无用状态。更重要的是,记忆化搜索还可以剪枝,这样一来,就大大降低了空间复杂度。
·接下来就是我调了半天的水题了:
相信大家一定都做过,这道题就是大名鼎鼎的“function”。
题目描述:
定义一个递归函数w(a,b,c),递归条件是这样的:
(1)如果a \le 0a≤0 or b \le 0b≤0 or c \le 0c≤0就返回值11.
(2)如果a>20a>20 or b>20b>20 or c>20c>20就返回w(20,20,20)w(20,20,20)
(3)如果a<ba<b并且b<cb<c 就返回w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c)w(a,b,c−1)+w(a,b−1,c−1)−w(a,b−1,c)
(4)其它的情况就返回w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1)w(a−1,b,c)+w(a−1,b−1,c)+w(a−1,b,c−1)−w(a−1,b−1,c−1)
这是一个简单的递归函数,但是实现起来可能会有些问题,比如当a、b、c都是15的时候调用的次数非常多,必须想一个办法!
题目分析:
这个办法就是“记忆化搜索”。根据(2)可以初步确定要将20以内的状态存下来,这样一来,每次遍历到这个状态时,就不用再去计算,直接返回已经存好的状态就可以啦!
代码实现:
1 #include<cstdio> 2 #include<iostream> 3 #define ll long long 4 5 using namespace std; 6 7 ll a,b,c; 8 ll ans[30][30][30]; 9 10 ll function(ll x,ll y,ll z) 11 { 12 if(x<=0||y<=0||z<=0) return 1; 13 if(x>20||y>20||z>20) return function(20,20,20); 14 if(ans[x][y][z]!=0) return ans[x][y][z];//如果这个情况已经被存在了ans数组中,那么就直接返回此状态下数组的值 15 if(x<y&&y<z) ans[x][y][z]=function(x,y,z-1)+function(x,y-1,z-1)-function(x,y-1,z); 16 else return ans[x][y][z]=function(x-1,y,z)+function(x-1,y-1,z)+function(x-1,y,z-1)-function(x-1,y-1,z-1);//将各种状态存到ans数组中 17 return ans[x][y][z]; 18 } 19 20 int main() 21 { 22 while(1)//如果不在循环中加上return 0,就会一直不停的读下去 23 { 24 scanf("%lld%lld%lld",&a,&b,&c); 25 if(a==-1&&b==-1&&c==-1) return 0;读到-1,-1,-1时直接结束程序 26 printf("w(%lld, %lld, %lld) = ",a,b,c); 27 if(a>20) a=21; 28 if(b>20) b=21; 29 if(c>20) c=21;//减少不必要的计算 30 printf("%lld\n",function(a,b,c)); 31 } 32 }
·总结:
记忆化搜索本质上是一种dp思想,但是又比dp快一点的算法,可以运用在在考试和平时做题时。
对了,还有一件事,一定要看好输出格式,比如这道题我就没有换行,导致WA了三次TwT。