01 故事起源有一天小K去滑雪,雪山高低不平,当然小K只能从高的地方向低的地方滑,那如何选择路线才能滑的最远呢? 把这个问题抽象描述如下:
int find(int i,int j){ // 向4个方向尝试 for (i=0->3){ if (ok){ return find(next)+1 } } } int main(){ for (i=0->n) { for (j=0->m) { t=find(i,j) ans=max(ans,t) } } } 03 问题上面的做法可以得到最优解,但有一个问题。如下例,以15为起点的时候,会尝试把6->5->4->3->2->1走一遍。但以16为起点的时候,还会尝试把这条路线走一遍,这就会导致大量的重复计算。 那能不能优化呢? 之所以重复计算,是因为每一次尝试都是重新的开始,它并不知道这条路已经走过了,也就是没有记忆,所以我们引入一种优化的方法,就是记忆化搜索。 04 记忆化搜索可以引入一个f[i][j]数组,记录以(i,j)为起点所能找到的最长路线的长度,初始赋值为-1,表示还没有走过。 当走过一点,就将对应的f[i][j]更新为以(i,j)为起点的最大长度。 再回到上面的问题,因为之前肯定走过了(2,3),对应的f[2][3]为6,当尝试从(2,4)出发时,会发现周围已经走过了,只需要更新当前的值+1即可,就避免了重复计算。 05 代码实现路线搜索
int find(vector<vector<int>> &snowMountain, vector<vector<int>> &f, int i, int j, int r, int c) { int x, y; if (f[i][j] != -1) return f[i][j]; f[i][j] = 1; for (int k = 0; k < 4; k++) { x = i + direction[k][0]; y = j + direction[k][1]; //valid direction if (x >= 0 && x < r && y >= 0 && y < c && snowMountain[i][j] > snowMountain[x][y]) { f[i][j] = maxOfTwo(f[i][j], find(snowMountain, f, x, y, r, c) + 1); } } return f[i][j]; }main函数
int main() { ifstream fin("a.in"); ofstream fout("a.out"); int i, j, r, c, maxHeight = 0; fin >> r >> c; vector<vector<int>> snowMountain(r, vector<int>(c, 0)); vector<vector<int>> f(r, vector<int>(c, -1)); for (i = 0; i < r; i++) for (j = 0; j < c; j++) fin >> snowMountain[i][j]; for (i = 0; i < r; i++) for (j = 0; j < c; j++) { maxHeight = maxOfTwo(maxHeight, find(snowMountain, f, i, j, r, c)); } fout << maxHeight << endl; fin.close(); fout.close(); return 0; } 06 总结记忆化搜索是一种非常实用的算法,因为深搜用递归很容易实现,记忆化又避免了重复子问题的计算,提高了运行效率。 这其实就是动态规划的思想,常见的动态规划用递推实现,相比记忆化搜索实现上会更难一点,而记忆化搜索就没有这个问题。 算法的适用场景也需要根据具体的问题来分析,一般常用在地图或者树型结构中。 审核编辑 :李倩
全部0条评论
快来发表一下你的评论吧 !