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

本文探讨了如何在二维数组中寻找最长的滑坡路径,通过记忆化搜索和动态规划两种方法解决滑雪区域中从最高点下滑至最低点的问题。算法通过比较相邻点的高度差,确定可行的滑行路径,并计算出最长路径的长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

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

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−124−17−16−12417161
24−17−16−124−17−16−12417161。当然25−24−23−...−3−2−125−24−23−...−3−2−1252423...321

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


Input
输入的第一行表示区域的行数RRR
RRR和列数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)。下面是RRR行,每行有CCC个整数,代表高度hh,0<=h<=10000hh,0<=h<=10000hh0<=h<=10000

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


解题思路

  • 记忆化搜索:
    在这里插入图片描述
  • DP:DP :DP: 因为必须从低到高,所以可以记录每个点的位置,然后排序矩阵。每个点扩展四个点,如果可以到达,那么更新四个方向。
    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)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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值