动态规划是自底向上的,先处理子问题,然后再处理更大的问题。这样就需要知道子问题和更大的问题之间的联系。我们能够确定出子问题并且能够正确的求解它,从而从子问题推出要解决的问题的解。
但是,如果当我们比较难确定出子问题是哪一个,比较困难的求出子问题的答案时,可以使用记忆化搜索
以洛谷上的滑雪题为例
对于这道题,我们没办法马上求得到达某个点的最长长度
因此我们需要使用递归方法,并且使用记忆化搜索来进行优化
思路
使用递归计算出,到x,y点的最长滑坡长度
遍历点(x,y)的上下左右四个点,如果一个点的值是小于点(x,y),说明这个点可以滑到点(x,y)
答案为,四个点中最长滑坡长度的最大值+1
res = max(res,getMax(newx,newy)+1);
使用循环更新数组的值,直到数组所有的值都被更新,找到数组中最大的那个值
代码
#include <iostream>
#include <vector>
using namespace std;
/**
输入
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
*/
int memo[105][105];
int quyu[105][105];
int R,C;
bool inArea(int x, int y )
{
return x>=1 && y>=1 && x<=R && y<=C;
}
//到x,y点的最长滑坡长度
int d[4][2] ={0,-1,1,0,-1,0,0,1};
int getMax(int x,int y)
{
//上下左右四个点中可达该点的数
if(memo[x][y]!=-1) return memo[x][y];
int res = 1;
for(int i=0; i<4; i++)
{
int newx = x+d[i][0];
int newy = y+d[i][1];
if(inArea(newx,newy) && quyu[x][y]>quyu[newx][newy])
{
res = max(res,getMax(newx,newy)+1);
}
}
memo[x][y] = res;
return res;
}
int main()
{
cin>>R>>C;
for(int i=1; i<=R; i++)
{
for(int j=1; j<=C; j++)
cin>>quyu[i][j];
}
int res = 0;
for(int i=0; i<105; i++)
for(int j=0; j<105; j++)
memo[i][j]=-1;
for(int i=1; i<=R; i++)
{
for(int j=1; j<=C; j++)
{
if(memo[i][j]==-1)
res=max(res,getMax(i,j));
else
res=max(res,memo[i][j]);
}
}
cout<<res<<endl;
return 0;
}