[刷题笔记] Luogu P1434 滑雪
Description
可以理解为二维最长下降子序列?
Solution
最简单的做法是直接暴力dfs,由于题目没有告知从哪出发,故将每一个点都作为出发点dfs,取max即可。
由于数据很水,可以获得90pts的好成绩(
个人认为本题正解有两种,记忆化搜索和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\)。(通俗一点就是当前点的行号*总共列数+当前点所处第几列)
如果还不理解我们来画图举例:
显然红色点在第三行第三列。自己理解一下吧。
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;
}
本文作者:SXqwq,转载请注明原文链接:https://www.cnblogs.com/SXqwq/p/17547345.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!