【洛谷P1434】滑雪

该博客详细介绍了洛谷P1434题目的解法,即寻找二维数组中滑雪时最长的下坡路径。作者提供了两种解题思路:一种是采用记忆化搜索,遍历所有节点并用数组记录;另一种是通过动态规划,将二维数组展开成一维并排序,然后找出最长路径。博客包含输入输出格式、样例以及对应的程序实现,并提到了解题过程中的关键点,即同一高度无法滑过。

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

滑雪


题目链接:滑雪

题目描述

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开始,在1结束)。当然25-24-23-…-3-2-1更长。事实上,这是最长的一条。

输入格式

输入的第一行为表示区域的二维数组的行数R和列数C(1≤R,C≤100)。下面是R行,每行有C个数,代表高度(两个数字之间用1个空格间隔)。

输出格式

输出区域中最长滑坡的长度。

输入输出样例

输入

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

解题思路①

这道题可以用记忆化搜索的方法来做将每一个节点的值都求一遍,用数组标记,最后取出最大值,输出答案

程序如下:

#include<cstdio>
#include<iostream>
using namespace std;
int n,m,a[110][110],f[110][110],maxn;
const int fx[5]={0,-1,1,0,0};
const int fy[5]={0,0,0,1,-1};
int dfs(int x,int y)//搜索
{
	if(f[x][y])//记忆化
		return f[x][y];
	for(int i=1;i<=4;i++)
		if(a[x+fx[i]][y+fy[i]]<a[x][y]&&x+fx[i]<=n&&x+fx[i]>0&&y+fy[i]>0&&y+fy[i]<=m)//判断是否合法
			f[x][y]=max(dfs(x+fx[i],y+fy[i])+1,f[x][y]);
	return f[x][y]; 
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			f[i][j]=dfs(i,j);
			if(f[i][j]>maxn)//取最大值
				maxn=f[i][j];
		}
	cout<<maxn+1<<endl;//因为本身也算一个节点
}

解题思路②

同样的,这道题也是一个动态规划,从高度较低的点向高度较高的点推,再找到最大的点,输出它的值。但是动态规划必须是有序的,所以在这里作者将这个二维的数组展开成一维的,进行排序后它就有序了。

程序如下:

#include<iostream>
#include<algorithm> 
#include<cstdio>
using namespace std;
int n,m,t[10010],maxn;
const int fx[5]={0,-1,1,0,0};
const int fy[5]={0,0,0,1,-1};
struct xy{
	int b;//值
	int x;//横坐标
	int y;//纵坐标
}f[10010];
bool bi(xy q,xy p)
{
	return q.b<p.b;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&f[(i-1)*m+j].b);
			f[(i-1)*m+j].x=i;f[(i-1)*m+j].y=j;//预处理
		}
	sort(f+1,f+n*m+1,bi);//排序
	for(int i=1;i<=n*m;i++)//枚举全部
		for(int j=i-1;j>0;j--)//从高到低
			for(int k=1;k<=4;k++)//四个方向
				if(f[i].x==f[j].x+fx[k]&&f[i].y==f[j].y+fy[k]&&f[i].b>f[j].b)//判断是否合法
				{
					t[i]=max(t[j]+1,t[i]);//动态转移
					if(t[i]>maxn)//取最大值
						maxn=t[i];
				}
	cout<<maxn+1;//因为本身也算一个节点
}

这里其实有一个需要注意的点:同一高度是滑不过去的。

分享

作者刷红的一片天
作者刷红的一片天

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值