滑雪【DP】【记忆化搜索】

Description

Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。 M i c h a e l 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 24−17−16−1 2417161
24 − 17 − 16 − 1 24−17−16−1 2417161。当然 25 − 24 − 23 − . . . − 3 − 2 − 1 25−24−23−...−3−2−1 252423...321

25 − 24 − 23 − . . . − 3 − 2 − 1 25−24−23−...−3−2−1 252423...321更长。事实上,这是最长的一条。


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

0 < = h < = 10000 0<=h<=10000 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


解题思路

  • 记忆化搜索:
    在这里插入图片描述
  • D P : DP : DP: 因为必须从低到高,所以可以记录每个点的位置,然后排序矩阵。每个点扩展四个点,如果可以到达,那么更新四个方向。
    f [ x + w x [ i ] ] [ y + w y [ i ] ] = m a x ( f [ x + w x [ i ] ] [ y + w y [ i ] ] , f [ x ] [ y ] + 1 ) f[x+wx[i]][y+wy[i]]=max(f[x+wx[i]][y+wy[i]],f[x][y]+1) f[x+wx[i]][y+wy[i]]=max(f[x+wx[i]][y+wy[i]],f[x][y]+1)

代码

DP:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int r,c;
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};
int p[500][500],p1[500][500]={1}; 
int k=0;
struct s{
	int a,b,c;
}bsy[100010];
bool cmp(const s&k,const s&l) 
{
    return k.a<l.a;
} 
void dp(){
	for(int i=1;i<=k;i++){
		for(int j=1;j<=4;j++)
		{
			if(bsy[i].b+dx[j]<=r&&bsy[i].b+dx[j]>0&&bsy[i].c+dy[j]>0&&bsy[i].c+dy[j]<=c)//如果可以到达
			{
				if(p[bsy[i].b+dx[j]][bsy[i].c+dy[j]]<p[bsy[i].b][bsy[i].c])
				p1[bsy[i].b][bsy[i].c]=max(p1[bsy[i].b][bsy[i].c],p1[bsy[i].b+dx[j]][bsy[i].c+dy[j]]+1);//更新
			}
		}
	}
}
int main(){
	cin>>r>>c;
	for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
		{
			cin>>p[i][j];
			k++;
			bsy[k].a=p[i][j];
			bsy[k].b=i;
			bsy[k].c=j;//记录位置
		}
	}
	sort(bsy+1,bsy+k+1,cmp);//排序
	dp();
	int ans=-1000000000;
    for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
		ans=max(ans,p1[i][j]);
	}
	cout<<ans+1;
}

记忆化搜索:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int r,c;
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};
int p[500][500],bsy[510][510]; 
int dfs(int x,int y)
{
	if(p[x][y])
	return p[x][y];//如果这个点找过了,就直接返回
	for(int i=1;i<=4;i++)
	{
		if(x+dx[i]<=r&&x+dx[i]>0&&y+dy[i]<=c&&y+dy[i]>0&&bsy[x+dx[i]][y+dy[i]]<bsy[x][y])
		{
			p[x][y]=max(p[x][y],dfs(x+dx[i],y+dy[i])+1);//更新最大值
		}
	}
	if(!p[x][y])//如果四个方向都不行,赋1
	p[x][y]=1;
	return p[x][y];
}
int main(){
	cin>>r>>c;
	int n,ans=-1000000000;
	int k=0;
	for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
			cin>>bsy[i][j];
	}
    for(int i=1;i<=r;i++)
	{
		for(int j=1;j<=c;j++)
		ans=max(ans,dfs(i,j));
	}
	cout<<ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值