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;
}
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)