[刷题笔记] Luogu P1434 滑雪

Problem

Description

可以理解为二维最长下降子序列?

Solution

最简单的做法是直接暴力dfs,由于题目没有告知从哪出发,故将每一个点都作为出发点dfs,取max即可。
由于数据很水,可以获得90pts的好成绩(
image

个人认为本题正解有两种,记忆化搜索和dp

记搜

记搜同样需要从每个点出发,显然每次搜索有四种方向,对于每个点如果还没有记搜则搜索四个方向(如果可行),记录向这四个方向滑雪路径最大,同时取max即可。

为什么记搜可行呢?显然如果再次滑到一个点但长度不如上次,则一定不是max,就没有必要继续搜索了。

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 10010
using namespace std;
int n,m;
int mapp[N][N];
int rem[N][N];
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int ans = -1;
int dfs(int x,int y,int last)
{
	if(rem[x][y]) return rem[x][y];
	int maxn = 0;
	for(int i=0;i<4;i++)
	{
		int ax = x+dx[i];
		int ay = y+dy[i];
		if(ax>0&&ax<=n&&ay>0&&ay<=m&&mapp[ax][ay] < last)
		{
			maxn = max(maxn,dfs(ax,ay,mapp[ax][ay])); //取四个方向上的max
		}
	}
	rem[x][y] = maxn+1; //记录当前点的max
	ans = max(ans,rem[x][y]);
	return rem[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",&mapp[i][j]);}
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++) 
		{
			dfs(i,j,mapp[i][j]); //和暴搜同理,从每一个点出发搜,不需要每次memset记忆化数组,因为先前的记忆化还可用于后面,降低复杂度。
		}
	}
	cout<<ans<<endl;
	return 0;
}

dp

其实明白了记搜dp就比较好想。

容易得到状态转移方程:若设\(dp[i][j]\)为以\((i,j)\)点为结尾的路径最大值,\(dp[a][b]\)为则满足:

\(dp[i][j] = max(dp[i][j],dp[a][b]+1)\)

在dp的过程中,我们需要确保从低处往高处递推,因为这样才能确保搜到高处的时候能利用低处的长度。

那么显然我们需要对高度进行排序。

由于滑雪场是二维的,sort排序不便,我们需要定义一个结构体,将二维转换成一维存储排序。(因为我们不仅需要高度,还需要记录每个点的坐标)

如何将二维坐标转换成一维呢?

假设滑雪场有\(n\)\(m\)列,那么\((i,j)\)点转换成一维就是\(i\times m+n\)。(通俗一点就是当前点的行号*总共列数+当前点所处第几列)
如果还不理解我们来画图举例:
image

显然红色点在第三行第三列。自己理解一下吧。


Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#define N 1010
using namespace std;
struct Node
{
	int i,j,h;
}qwq[N];
int dp[N][N],mapp[N][N];
int n,m;
int maxn = -1;
bool cmp(Node a,Node b)
{
	return a.h < b.h;
}
int dx[4] = {0,0,1,-1};
int dy[4] = {1,-1,0,0};
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<m;j++) 
		{
			scanf("%d",&mapp[i][j]);
			dp[i][j] = 1;
			qwq[i*m+j].h = mapp[i][j];
			qwq[i*m+j].i = i;  //将二维坐标转换成一维存储
			qwq[i*m+j].j = j;
		}
	}
	sort(qwq,qwq+n*m,cmp);//排序
	for(int i=0;i<n*m;i++) //显然共有n*m个点
	{
		for(int j=0;j<4;j++) //四个方向
		{
			int ax = qwq[i].i+dx[j],ay = qwq[i].j+dy[j];
			if(ax>=0&&ax<=n&&ay>=0&&ay<=m&&mapp[ax][ay] < mapp[qwq[i].i][qwq[i].j])
			{
				dp[qwq[i].i][qwq[i].j] = max(dp[qwq[i].i][qwq[i].j],dp[ax][ay]+1);
			}
		}
	}
	for(int i=0;i<n;i++) //取max
	{
		for(int j=0;j<m;j++) maxn = max(maxn,dp[i][j]);
	}
	cout<<maxn<<endl;
	return 0;
}
posted @   SXqwq  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示