记忆化搜索
1.记忆化搜索的思想
记忆化搜索的思想是,在搜索过程中,会有很多重复计算,如果我们能记录一些状态的答案,就可以减少重复搜索量
2、记忆化搜索的适用范围
根据记忆化搜索的思想,它是解决重复计算,而不是重复生成,也就是说,这些搜索必须是在搜索扩展路径的过程中分步计算的题目,也就是“搜索答案与路径相关”的题目,而不能是搜索一个路径之后才能进行计算的题目,必须要分步计算,并且搜索过程中,一个搜索结果必须可以建立在同类型问题的结果上,也就是类似于动态规划解决的那种。
也就是说,他的问题表达,不是单纯生成一个走步方案,而是生成一个走步方案的代价等,而且每走一步,在搜索树/图中生成一个新状态,都可以精确计算出到此为止的费用,也就是,可以分步计算,这样才可以套用已经得到的答案
3、记忆化搜索的核心实现
a. 首先,要通过一个表记录已经存储下的搜索结果,一般用哈希表实现
b.状态表示,由于是要用哈希表实现,所以状态最好可以用数字表示,常用的方法是把一个状态连写成一个p进制数字,然后把这个数字对应的十进制数字作为状态
c.在每一状态搜索的开始,高效的使用哈希表搜索这个状态是否出现过,如果已经做过,直接调用答案,回溯
d.如果没有,则按正常方法搜索
4、记忆化搜索是类似于动态规划的,不同的是,它是倒做的“递归式动态规划”。
求二项式系数
简单递归
int bino(int n,int r){
if(r == 0|| n == r) return 1;
return bino(n-1,r-1) + bino(n-1,r);
}
记忆化
int cache[30][30];//初始为1
int bino2(int n,int r){
if(r ==0 || n == r) return 1;
if(cache[n][r] != -1)
return cache[n][r];
//直接计算并保存到数组
return cache[n][r] = bino2(n-1,r-1) + bino2(n-1,r);
}
采用引用的方法
适用于多维时下标较乱的时候
int cache[30][30];//初始为1
int bino2(int n,int r){
if(r ==0 || n == r) return 1;
int & ret = cache[n][r]; //引用型
if(ret != -1)
return ret;
//直接计算并保存到数组
return ret = bino2(n-1,r-1) + bino2(n-1,r);
}
三角形的最大路径
题意
有个以自然数排列而成的三角形。从最上面的数开始,每次向下或右下走一步,最终到达底部。每次可向下或向右下走一步。请在所有路径中找出数值之和最大的路径,并求出这个和。
代码:
int n,triangle[100][100];
int cache[100][100];
// 返回从 x,y其实到底部路径的最大值
int path(int x,int y){
if(y == n-1)return triangle[x][y];
int & ret = triangle[x][y];
if(ret != -1)return ret;
//可以这么理解,每一个小路径都是最大的,那么总的就是最大的
return ret = max(path(x,y+1),path(x+1,y+1)) + triangle[x][y];
}
利用迭代动态规划求三角形的最大路径
int n,triangle[100][100];
int C[100][100];
int iterative(){
for(int x =0;x<n;++x)
C[n-1][x] = triangle[n-1][x];;
for(int y = n-2;y>=0;--y)
for(int x=0;x<y+1;++x)
C[y][x] = max(C[y+1][x],C[y+1][x+1] + triangle[y][x]);
return C[0][0];
}
三角形最大路径的个数
思路,对于下边如果大于右下角的,那么路径数就是下边的,反之则是右下角,但如果两者相同,那么就是一样的,两边都加。
int countCache[100][100];
int count(int x,int y){
if(y == n-1)return 1;
int & ret = countCache[x][y];
if(ret != -1)
return ret;
ret = 0;
if(path(x,y+1)>=path(x+1,y+1)) ret += countCache(x,y+1);
if(path(x+1,y+1)>=path(x,y+1)) ret += countCache(x+1,y+1);
return ret;
}