记忆搜索

从字面来理解,记忆搜索就是按照记忆搜索,当某些循环太多了,但是我们可以找到在循环的过程中,

我们会多次来到每个节点,会多次计算这个节点,这个时候我们就可以将这个节点存下来,在下一次

访问的时候,就不用再来计算这个节点了,可以直接利用。这个就是就是俗称的记忆化搜索,开始自己

听到这个词的时候也是懵逼的,但是做到某些题的时候用起来还是比较方便的,这样可以节省很多时间。

下面我们看来一个题,对于初学者可能有点难哦,...............(表示自己第一次做也是看了题解才会做的。)

题目描述

对于一个递归函数w(a,b,c)w(a,b,c)w(a,b,c)

  • 如果a≤0a \le 0a0 or b≤0b \le 0b0 or c≤0c \le 0c0就返回值111.
  • 如果a>20a>20a>20 or b>20b>20b>20 or c>20c>20c>20就返回w(20,20,20)w(20,20,20)w(20,20,20)
  • 如果a<ba<ba<b并且b<cb<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)w(a,b,c1)+w(a,b1,c1)w(a,b1,c)
  • 其它的情况就返回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)w(a1,b,c)+w(a1,b1,c)+w(a1,b,c1)w(a1,b1,c1)

这是个简单的递归函数,但实现起来可能会有些问题。当a,b,ca,b,ca,b,c均为15时,调用的次数将非常的多。你要想个办法才行.

/* absi2011 : 比如 w(30,−1,0)w(30,-1,0)w(30,1,0)既满足条件1又满足条件2

这种时候我们就按最上面的条件来算

所以答案为1

*/

输入输出格式

输入格式:

 

会有若干行。

并以−1,−1,−1-1,-1,-11,1,1结束。

保证输入的数在[−9223372036854775808,9223372036854775807][-9223372036854775808,9223372036854775807][9223372036854775808,9223372036854775807]之间,并且是整数。

 

输出格式:

 

输出若干行,每一行格式:

w(a, b, c) = ans

注意空格。

 

输入输出样例

输入样例#1: 复制
1 1 1
2 2 2
-1 -1 -1
输出样例#1: 复制
w(1, 1, 1) = 2
w(2, 2, 2) = 4

说明

记忆化搜索

在开始的时候,我是按照题目要求直接将这些递归函数写好,但是在运行的时候时间就爆了;

这是才发现如果这样做的话这个递归就会做很多次,但是很多都会是重复的计算,所以这个时候我们就可以

用到记忆化搜索。

AC代码:

#include<iostream>
#include<cstring>
using namespace std;
long long rpd[25][25][25];//存放已经计算过的数, 
long long w(long long a,long long b,long long c)
{
    if(a<=0||b<=0||c<=0) return 1;
    else if(rpd[a][b][c]!=0) return rpd[a][b][c];//判断该组数据的a,b,c是否已经被计算过,如果计算过直接调用; 
 else if(a>20||b>20||c>20)  rpd[a][b][c]=w(20,20,20);//将每一个大于20的数计算出来并存放进数组中; 
 else if(a<b&&b<c)  rpd[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);//将计算出来的w(a,b,c)存进三维数组的相应下标 
 else  rpd[a][b][c]=w(a-1,b,c)+w(a-1,b-1,c)+w(a-1,b,c-1)-w(a-1,b-1,c-1);
 return rpd[a][b][c];
}
int main()
{    
    
 long long a,b,c,x,y,z;
 while(1)
 { 
 memset(rpd,0,sizeof(rpd));
 cin>>a>>b>>c;
 if(a==-1&&b==-1&&c==-1) break;
 x=a;
 y=b;
 z=c;
 if(a>20) x=21;//超过20的会是一个答案,所以将他记录在同一个位置。
 if(b>20) y=21;
 if(c>20) z=21;
 cout<<"w("<<a<<", "<<b<<", "<<c<<") = "<<w(x,y,z)<<endl;
 }
 return 0;
}

 

 

 

 

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

posted @ 2019-07-05 14:20  香格里拉太子zo  阅读(287)  评论(0编辑  收藏  举报