POJ 1088 滑雪(动态规划)(记忆化搜索)

滑雪

Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子

 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


一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-...-3-2-1更长。事实上,这是最长的一条。

Input

输入的第一行表示区域的行数R和列数C(1 <= R,C <= 100)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。

Output

输出最长区域的长度。

Sample Input

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

Sample Output

25

题解:动态规划问题,采用记忆化搜索。利用一个数组存储每个点的最大值,每个点的最大值都与周围四个方向较小的最大值有关。每个点都要判断它的上,下,左,右四个方向,分别得到从四个方向出发的路径长度,找出其中最大的,加1后存入当前点,即为该点的最大路径长度。按照上,右,下,左四个方向判断,对于每个方向都要判断高度是否小于当前高度,如果小于的话,判断路径长度是否为0,如果为0则递归到这个方向点,递归返回的是路径长度,如果不为0,则将路径长度记录下来,最后在四个方向中找出最大的路径长度,加1作为该点的最大路径长度。

具体代码如下:

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[102][102];
int a[102][102];
int dir[4][2]={{0,1},{0,-1},{-1,0},{1,0}};
int Max(int i,int j)
{
	if(a[i][j]>=a[i-1][j]&&a[i][j]>=a[i+1][j]&&a[i][j]>=a[i][j-1]&&a[i][j]>=a[i][j+1])
		return 0;
	return 1;	
}
int DFS(int i,int j)
{ 
	int M=0;
	if(dp[i][j]!=0)
		return dp[i][j];
	if(Max(i,j))//如果a[i][j]和四周比是最小的
//这里比较难理解,如果是最小的,就没有前一个dp[i][j]让它去继承,
//所有需要返回1,也就是说这里的dp[i][j]=1 ,表示到这里之前是没有路的 
		return 1;
	for(int t=0;t<4;t++)//找到前一个dp[i][j]去继承,即+1 
		if(a[i+dir[t][0]][j+dir[t][1]]<a[i][j])
			M=max(DFS(i+dir[t][0],j+dir[t][1])+1,M);
	return M;
}
int main()
{
	int n,m;
	cin>>n>>m;
	int i,j;
	memset(a,1,sizeof(a));
	memset(dp,0,sizeof(dp));
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			cin>>a[i][j];
	DFS(1,1);
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			dp[i][j]=max(DFS(i,j),dp[i][j]); 
	int sum=0;
	for(i=1;i<=n;i++)
		for(j=1;j<=m;j++)
			sum=max(dp[i][j],sum); 
	cout<<sum<<endl;
	return 0;
}

DP和DFS的结合,博主也是第一次见,理解了半天才懂,刚学动态规划,这题应该算难的吧。有什么问题可以在下面评论一起讨论讨论,一起进步。。。

猜你喜欢

转载自blog.csdn.net/qq_42391248/article/details/81227263