1.记忆化搜索的作用
记录每一次搜索对象的返回值,以后递归搜索中若再次出现该对象,则可直接引用之前存储的值,不必再次对该对象进行递归求值。该方法极大程度上优化了时间复杂度,减少不必要的递归。
2.如何使用
在该递归结束前(及return的上一步),使用数组记录下要return的变量。
例如:
int dfs(int x)
{
...
...
...
for (......)
ans=...
a[x]=ans;
return ans;
}
3.例题
(1)洛谷P1028:数的计算
#include<cstdio>
int N;
int a[1010];
int f(int x)
{
int i,s=1;
if (a[x]!=0)
return a[x];
for (i=x/2;i>=1;i--)
{
s+=f(i);
a[x]=s;
}
return s;
}
int main()
{
int ans;
scanf("%d",&N);
a[1]=1;
ans=f(N);
printf("%d",ans);
return 0;
}
#代码分析
1.for循环中s+=f(i),每一个f(i)的值都是i这个数能产生的子集数
2.i以x/2作为初始值进入循环,s+=f(i)立即再次调用递归函数,以此类推,直到调用到1,在 逐步退出来。
3.a[x]在从1开始逐步退出来之前,记录该次的答案。
(2)洛谷P1464:Function
#include<stdio.h>
typedef long long ll;
int w[30][30][30],book[30][30][30];
int f(ll a,ll b,ll c)
{
if (a<=0 || b<=0 || c<=0) //特殊情况1
return 1;
if (a>20 || b>20 || c>20) //特殊情况2
return f(20,20,20);
if (book[a][b][c]!=0) //记忆答案:!=0说明已搜索过,存了数值
return w[a][b][c];
if (a<b && b<c)
w[a][b][c]=f(a,b,c-1)+f(a,b-1,c-1)-f(a,b-1,c);
else
w[a][b][c]=f(a-1,b,c)+f(a-1,b-1,c)+f(a-1,b,c-1)-f(a-1,b-1,c-1);
book[a][b][c]=1;
return w[a][b][c];
}
int main()
{
ll a,b,c;
int ans;
while (1)
{
scanf("%lld %lld %lld",&a,&b,&c);
if(a==-1 && b==-1 && c==-1)
return 0;
ans=f(a,b,c);
printf("w(%lld, %lld, %lld) = %d\n", a, b, c,ans);
}
return 0;
}