5 5 1 2 3 4 5 16 17 18 19 6 15 24 25 20 7 14 23 22 21 8 13 12 11 10 9[输出样例]
25[解题思路]
给出一个m*n的矩阵grid,每一格代表一个高度,要求我们找到一条路径,满足高度严格递减且长度最长。显然,对于这种问题,我们可以枚举起点,并通过dfs来得到最长的路径。
对于dfs的过程也很好理解:向上下左右四个方向搜索,若下一格的高度小于本格,则继续搜索且长度++,直到找出最长的路径。
但是,以题目给出的这个样例为例,假如我们使用上述方法会出现一个巨大的漏洞(此处以(i,j)表示grid[i][j]的单元格):
假如我们从(0,0)开始搜索,由于四周没有比1小的数,搜索直接结束。
接下来,我们从(0,1)开始搜素,搜索路径为(0,1)->(0,0),共调用两层递归。
接下来,我们从(0,2)开始搜索,搜索路径为(0,2)->(0,1)->(0,0),共调用三层递归。
............
不难发现,按照这种方式继续下去,仅(0,0)处就被搜索了数十次,这在时间上是一个非常巨大的损耗,倘若我们的grid数组非常大,那么由于重复搜索消耗的时间是难以估量的。
因此,我们需要采取一个手段来避免这种时间的损耗:记忆化搜索。简单来说,就是另外使用一个容器来存储各点的路径最大值。这样的话,仅需执行过一次对本格的搜索,下一次重复检索本格时就可以直接从对应的容器中取值了。
最后,我们直接上代码,结合本题来理解一下记忆化搜索的便利:
#include#include using namespace std; int n, m;//矩阵的长宽 int dx[4] = { 1,0,-1,0 }, dy[4] = { 0,1,0,-1 };//搜索的四个方向 vector > mem;//用于记忆化存储 //传入搜索起始位置的横纵坐标x,y及矩阵grid int dfs(int x, int y, vector >& grid) { //如果已被记忆化存储,则直接返回 if (mem[x][y] != -1) return mem[x][y]; int ret = 1;//无论如何都要经过本格,因此初值设为1 //向四个方向搜索,求其路径最大值 for (int i = 0; i < 4; i++) { //越界判断 && 后一格的高度小于前一格 if (x + dx[i] >= 0 && x + dx[i] < n && y + dy[i] >= 0 && y + dy[i] < m && grid[x + dx[i]][y + dy[i]] < grid[x][y]) { ret = max(ret, dfs(x + dx[i], y + dy[i], grid) + 1);//注意路径+1 } } //更新mem数组 mem[x][y] = ret; //返回ret return ret; } int main() { //读取数据及初始化容器 int ans = 0; cin >> n >> m; vector > grid(n, vector (m)); mem = vector >(n, vector (m, -1));//初值为-1,表示未经过存储 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> grid[i][j]; } } //以每一个位置作为搜索起始位置,进行dfs搜索 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { //取其最大值 ans = max(ans, dfs(i, j, grid)); } } //输出结果 cout << ans; return 0; }


![[C++]洛谷 滑雪 dfs+记忆化搜索详解 [C++]洛谷 滑雪 dfs+记忆化搜索详解](http://www.mshxw.com/aiimages/31/861612.png)
