题目
思路:记忆化搜索
记忆化搜索的本质还是DP,但是实现方式和传统DP不一样,采用的是一种递归的实现方式。
(图片有误,转换中向上的公式和向下的公式颠倒了)
解释状态计算为什么可以这么算?
以向右滑举例:
如果在(i,j)(i,j)(i,j)处可以向右滑,那么f[i,j]=f[i,j+1]+1f[i,j]=f[i,j+1]+1f[i,j]=f[i,j+1]+1
如果可以向右滑,那么(i,j)(i,j)(i,j)处的高度一定大于(i,j+1)(i,j+1)(i,j+1)处以及它能滑到的路径上所有区域的高度
所以要求f[i,j]f[i,j]f[i,j],实际是求f[i,j+1]f[i,j+1]f[i,j+1],再+1+1+1
但是有四个方向可能可以滑,所以取这四个方向可能额可以滑的最大值。
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=310;
int h[N][N],f[N][N];
int r,c;
int dx[4]={1,-1,0,0},dy[4]={0,0,-1,1}; //上下左右移动位移方向数组
int dp(int x,int y)
{
int &v=f[x][y]; //用引用v来代替f[x][y]
if(v!=-1) return v; //如果v!=-1,证明v的值已经计算出来了,不用再算了,这一步很关键,省去了多余的计算,不然会TLE
v=1; //在滑向第一个区域前,每个点自身算一个区域
for(int i=0;i<4;i++) //遍历四个方向
{
int a=x+dx[i],b=y+dy[i];
if(a>=1&&a<=r&&b>=1&&b<=c&&h[x][y]>h[a][b]) //如果滑的方向的区域还在雪场内
v=max(v,dp(a,b)+1); //算最大值
}
return v;
}
int main()
{
scanf("%d%d",&r,&c);
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
scanf("%d",&h[i][j]);
memset(f,-1,sizeof(f)); //把dp数组初始化为0
int res=0; //记录结果
for(int i=1;i<=r;i++)
for(int j=1;j<=c;j++)
res=max(res,dp(i,j)); //算出以每个点为起点的最大路径长度,作比较算出其中最大的
printf("%d",res);
return 0;
}