记忆划搜索就是指在原来搜索的基础上,进行了速度和时间上的优化,多用了一个数组来存储每一个算出来的数值,再之后用到的时候直接调用就可以了,不用再次计算。
所以,这样可以极大地优化时间和空间。
经典习题:斐波那契数列:相信题目描述大家已经非常清楚了,关键步骤f(n)=f(n-1)+f(n-2)。
所以,我们可以得出一个递推的代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=10001;
int a[maxn],n;
int main(){
cin>>n;
a[1]=a[2]=1;
for(int i=3;i<=n;i++)
a[i]=a[i-1]+a[i-2];
cout<<a[n];
return 0;
}
第二种思路:递归
#include <bits/stdc++.h>
using namespace std;
int f(int x){
if(x==1||x==2)
return 1;
else
return f(x-1)+f(x-2);
}
int main(){
int n;
cin>>n;
cout<<f(n);
return 0;
}
第三种思路:记忆化搜索:这里每算一个f(n)就要算f(n-1)和f(n-2),如果是f(5),就要算f(4)和f(3),而在算f(4)的时候,要算f(3)和f(2),而这里,我们可以发现,在算f(4)+f(3)的时候,显然,再算f(4)的时候,f(3)就已经被算过了,为了不让f(3)再被重新算一次,用数组在计算的同时存下f(3)的值,到时候重新调用就是了,代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=10000+3;
int a[maxn];
int f(int x){
if(x==1||x==2)
return 1;
if(a[x])
return a[x];
else
return a[x]=f(x-1)+f(x-2);
}
int main(){
int n;
a[1]=a[2]=1;
cin>>n;
cout<<f(n);
return 0;
}
这样,我们就可以利用记忆化搜索来做题了!
https://www.luogu.org/problemnew/show/P1464
这一道题就是纯粹地让我们来练习记忆化搜索的,直接按照题目的意思,运用记忆化搜索,很快就能做出来了。
#include <bits/stdc++.h>
using namespace std;
const int maxn=50;
int p[maxn][maxn][maxn];
long long w(long long a,long long b,long long c){
if(a<=0||b<=0||c<=0)
return 1;
else if(a>20||b>20||c>20)
return w(20,20,20);
if(p[a][b][c]==1)
return p[a][b][c];
if(a<b&&b<c)
return p[a][b][c]=w(a,b,c-1)+w(a,b-1,c-1)-w(a,b-1,c);
else
return p[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);
}
int main(){
long long a,b,c;
while(1){
cin>>a>>b>>c;
if(a==-1&&b==-1&&c==-1)
break;
printf("w(%lld, %lld, %lld) = %lld\n",a,b,c,w(a,b,c));
}
return 0;
}