记忆化搜索$||dp||$剪枝

先讲方法,代码待会上

方法一:记忆化搜索

这个方法不怎么解释,就是每搜索完一个高度的最长路径记录一下,以后搜索其他的点时如果走到了这条路就直接用记录的值计算就是了

方法二:$dp$

假设一个点的高度为H,周围四个点的高度分别为$\mathcal{H1,H2,H3,H4,}$$f[i][j]$代表从$(i,j)$滑的最长长度。如果$\mathcal{H}$大于周围四个点的一个,那么就可以滑到那一个点,也就是$f$[高的那个点]$=f$[矮的那个点]$\mathcal{+1}$,到这里就不难写出状态转移方程了:$f[i][j]=f[i+b_g][j+c_g]+\mathcal{1}$(前提:$a[i+b_g][j+c_g]<a[i][j]$),其中$a$数组为读入的高度,$b$、$c$数组为方向数组,$f$数组为这个点的最长路径长度。注意在计算长度之前要先将高度排序,然后再来算

方法3:剪枝

假如说当前的最大高度为$maxn$,搜索函数里的参数$num$(代表当前已经走过的长度),当前这个点的高度为$height$。如果$num+height<=maxn$,那么可以直接$return$(注意:这里我还没有枚举周围四个点)。假设你从这个点可以一路无阻碍的走到$\mathcal{1}$(也就是最优的情况),那么从这个点走的长度为$height$。但是如果已经走的长度加上从这个点的最优长度都小于等于最大长度的话,那么搜下去肯定是毫无意义的,果断剪枝。

除了这个以外,还可以加一个小小的剪枝(与其说是剪枝,不如说是特判):如果$maxn==n*m$,那么就可以直接输出答案了。因为整个地图的大小为$n*m$,若$maxn==n*m$的话就说明可以跑完整个地图,那么最大值无论如何也不会更新了,所以说这里就可以直接输出了(说不定可以过某些测试点呢)

接着附上代码:(由于本人比较懒,$dp$的代码搬$(chao)$运$(xi)$的一本通)

方法一:$(\mathcal{42}ms/\mathcal{928}KB)$(不知道为什么我的记忆化是$\mathcal{42}ms$,大佬都是$\mathcal{0}ms$,可能我太蒟了吧)

#include<cstdio>
#include<iostream>
using namespace std;
const int N=105;
int n,m,a[N][N],f[N][N]= {0},maxn,ans,b[4]= {1,0,-1,0},c[4]= {0,1,0,-1};
bool p[N][N];
inline void dfs(int x,int y,int num) {
int flag=0;
for(int i=0; i<4; i++) {
int xx=x+c[i],yy=y+b[i];
if(a[xx][yy]>=a[x][y]) continue;
if(f[xx][yy]) {
ans=max(ans,f[xx][yy]+num);
continue;
}
if(xx&&xx<=n&&yy&&yy<=m&&!p[xx][yy]) {
p[xx][yy]=1;
dfs(xx,yy,num+1);
p[xx][yy]=0;
}
}
if(!flag) {
ans=max(ans,num);
return;
}
}
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++) {
ans=0;
p[i][j]=1;
dfs(i,j,1);
p[i][j]=0;
f[i][j]=ans;
if(maxn<ans) maxn=ans;
}
}
printf("%d\n",maxn);
return 0;
}

方法二:$(\mathcal{33}ms/\mathcal{792}KB)$

#include<iostream>
#include<cstdio>
using namespace std;
int dx[5]= {0,-1,0,1,0},dy[5]= {0,0,1,0,-1};
long long r,c,i,j,p,t,ans;
long long m[101][101],f[101][101];
int search(int,int);
int main() {
cin>>r>>c;
ans=0;
for(i=1; i<=r; i++) {
for(j=1; j<=c; j++) cin>>m[i][j];
}
for(i=1; i<=r; i++) {
for(j=1; j<=c; j++) {
t=search(i,j);
f[i][j]=t;
if(t>ans) ans=t;
}
}
cout<<ans<<endl;
}
int search(int x,int y) {
int i,t,tmp,nx,ny;
if(f[x][y]>0) return f[x][y];
t=1;
for(i=1; i<=4; i++) {
nx=x+dx[i];
ny=y+dy[i];
if((nx>=1)&&(nx<=r)&&(ny>=1)&&(ny<=c)&&(m[x][y]<m[nx][ny])) {
tmp=search(nx,ny)+1;
if(tmp>t) t=tmp;
}
}
f[x][y]=t;
return t;
}

方法三:$(\mathcal{988}ms/\mathcal{1040}KB)$

#include<cstdio>
using namespace std;
const int N=105;
int n,m,a[N][N],maxn,b[4]= {1,0,-1,0},c[4]= {0,1,0,-1};
bool p[N][N]= {0};
inline void dfs(int x,int y,int num) {
int flag=0;
if(a[x][y]+num<maxn) return;
for(int i=0; i<4; i++) {
int xx=x+c[i],yy=y+b[i];
if(xx>0&&xx<=n&&yy>0&&yy<=m) {
if(a[xx][yy]>=a[x][y]) continue;//跳不过去
if(!p[xx][yy]) {
flag=1;
p[xx][yy]=1;
dfs(xx,yy,num+1);
p[xx][yy]=0;
}
}
}
if(!flag) {
if(maxn<num) maxn=num;
return;
}
}
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++) {
if(maxn==n*m) {
printf("%d\n",maxn);
return 0;
}
p[i][j]=1;
dfs(i,j,1);
p[i][j]=0;
}
}
printf("%d",maxn);
return 0;
}

题解 [SHOI2002]滑雪的更多相关文章

  1. [BFS]P1434 [SHOI2002]滑雪

    P1434 [SHOI2002]滑雪 Description Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者 ...

  2. 洛谷[SHOI2002]滑雪题解

    什么破题啊 简直就是浪费我时间! 我每天还被我xf定目标了不知道嘛! 题目 朴素的搜索只能得90分 #include <cstdio> #include <iostream> ...

  3. 【dp】P1434 [SHOI2002]滑雪

    题目描述 Michael喜欢滑雪.这并不奇怪,因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在一个区域中最长 ...

  4. 【题解】滑雪 luogu1434 记忆化搜索

    记忆化搜索入门题 题目 Michael喜欢滑雪.这并不奇怪,因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在 ...

  5. P1434 [SHOI2002]滑雪

    题目描述 Michael喜欢滑雪.这并不奇怪,因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在一个区域中最长 ...

  6. P1434 [SHOI2002]滑雪 dfs

    题目描述 Michael喜欢滑雪.这并不奇怪,因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在一个区域中最长 ...

  7. 洛谷 P1434 [SHOI2002]滑雪

    这道题适合记忆化练手 毕竟总有些大佬虐题. 这个题有几个剪枝 1.记忆化 这个不用多说了吧 剪枝就是 如果 当前点到下面一个点的目前下降的高度+1 小于 下面那个点 能下降的高度 那么反过来,这个点不 ...

  8. 洛谷P1434 [SHOI2002]滑雪

    题目描述 Michael喜欢滑雪.这并不奇怪,因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道在一个区域中最长 ...

  9. 洛谷-P1434 [SHOI2002]滑雪 (记忆化搜索)

    题意:有一个\(R*C\)的矩阵,可以从矩阵中的任意一个数开始,每次都可以向上下左右选一个比当前位置小的数走,求走到\(1\)的最长路径长度. 题解:这题很明显看到就知道是dfs,但是直接爆搜会TLE ...

随机推荐

  1. 洛谷 P2114 [NOI2014]起床困难综合症 位运算

    题目描述 21世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm一直坚持与起床困难综合症作斗争.通过研究相关文献,他找到了该病的发病原因 ...

  2. Java入门系列之final

    前言 在C#经典面试中掺杂过Java的final关键字,主要用于类不能被继承,在C#则是利用关键字seal修饰类为密封类,而在Java中的final关键字的具体用法包含C#中const.readonl ...

  3. 【高并发】面试官问我如何使用Nginx实现限流,我如此回答轻松拿到了Offer!

    写在前面 最近,有不少读者说看了我的文章后,学到了很多知识,其实我本人听到后是非常开心的,自己写的东西能够为大家带来帮助,确实是一件值得高兴的事情.最近,也有不少小伙伴,看了我的文章后,顺利拿到了大厂 ...

  4. Pop!_OS配置JAVA环境

    Pop!_OS配置JAVA环境 #0x0 安装vscode #0x1 安装JDK #0x2 配置vscode #0x3 安装Eclipse #0x0 安装vscode 见Pop!_OS下安装C++编程 ...

  5. ASP.NET Core端点路由 作用原理

    端点路由(Endpoint Routing)最早出现在ASP.NET Core2.2,在ASP.NET Core3.0提升为一等公民. Endpoint Routing的动机 在端点路由出现之前,我们 ...

  6. JavaScript动画实例:螺旋线

    数学中有各式各样富含诗意的曲线,螺旋线就是其中比较特别的一类.螺旋线这个名词来源于希腊文,它的原意是“旋卷”或“缠卷”.例如,平面螺旋便是以一个固定点开始向外逐圈旋绕而形成的曲线.在2000多年以前, ...

  7. ”initialization failure:0x0000000C“错误,何解?

    今天开机后打开软件,报出这样的警告”initialization failure:0x0000000C“. 我问了度娘,看了很多回答,答案参差不齐.其中,有个回答还是很不错的(刚好我的是win10系统 ...

  8. Puppeteer爬虫实战(二)

    连接浏览器 上一篇说到了Puppeteer本质是使用了Chrome Devtools协议控制浏览器,本篇就说说连接方式. 常规Hook浏览器 此方式其实就是需要一个浏览器可执行文件(不同平台需要下载对 ...

  9. socket解决半包、粘包问题

    最近项目遇到socket服务端接收报文不全的问题,与其客户端约定的是报文长度+报文体.然而当客户端数据量大的时候,用分包发送,导致服务端报文日志接收不完整,于是想着先读出包体长度,再读出包体,不够就一 ...

  10. 基于python实现查询ip地址来源

    接口调用方法是在url后面直接加上IP地址. url = 'http://freeapi.ipip.net/218.192.3.42' #中文免费 url2 = 'http://ip-api.com/ ...