P1029 滑雪

245 阅读4分钟

JOB~C5}MNZYBN{8K5N}@B.gif

image.png

image.png

题目要求:

image.png

这么大的空间限制应该和深度优先搜索(暴力搜索(doge))沾边

image.png

题目中的例子应该是这个意思

image.png

从山顶滑下来路线最长的路是25

某一天,hyw去滑雪,问我最长的、最爽的一条路怎么滑?

image.png

下面,按照顺序思考

1. 首先,是不是从最高的点开始滑下来的。

显然不一定,比如这么一种地形:

image.png

1、2、3、4、5、6、7之间等距离

是红色的路线长度最长(这个题目考虑的是垂直距离,1到2的距离等于4到5的距离)

这就复杂了,得每一个点都深搜一遍,记录下最大的路线长度。

那为何不直接,每个点作为起点暴力搜索一下,总能找到答案的。

可惜会runtime error ,然后你就会和这个表情包一样

image.png

2.准备工作:

我这题的解题规范是左上角的点坐标为(1,1),右下角的为(R,C)!!!!!!

(数组的第一个元素的下标是0)

既然要遍历所有的点,那么:

image.png

先确定一个点比如24这个点

image.png

要动,就有四个方向:上下左右,hyw只有四种走法,上下左右,如果往上走,那么它的坐标变成了(x-1,y),往左变成(x,y-1),右(x,y+1),下(x+1,y),所以可以定义方向数组如下:

image.png

然后呢,有两种情况也是不符合实际的:

1、不能低处往高处滑

2、不能出界

image.png

关键点来了:

递归!

不过首先要先定义一个数组,它的作用是:

1、等于0说明这个点没有来过,不等于0说明这个点来过(走过的点不能再走)

2、假如maxlen[x][y]==5,说明点(x,y)接下来最长的路是5

什么意思?这个地方需要倒过来想,最后一个点的maxLen是1,倒数第二个是2,以此类推

接下来模拟一下,假如你到了一个新的点:

判断maxLen是不是0

(1)不是0的话说明走过了,并且返回这个点的maxLen值,表示接下去的最长路径

image.png

(2)是0,先标记一下1,说明到此一游,然后往四个方向各试一遍,比较是四个方向的其中一个点+1最长,还是我这个点接下去的最长路径长(现在不懂没关系,看完下面的具体例子再回来看应该懂了)

image.png

把这个过程包装成方法dfs(dfs——deepth first search深度优先搜索)对每个点用一次,找出最大值

image.png

image.png

具体例子:

5*5的矩阵: ----此时的maxLen[][]:

image.png image.png

开始遍历:

初始值dis==1

点[1][1]由于周围要么是1要么越界所以dfs一次之后变为:

矩阵:------------- 此时的maxLen[][]:

image.png image.png

这种情况会一直持续到[3][2]:

矩阵:------------- 此时的maxLen[][]:

image.png image.png

然后开始[3][3]:

矩阵:------------- 此时的maxLen[][]:

image.png image.png

根据这个步骤

image.png

maxLen[3][3]是0,令maxLen[3][3]=1;

矩阵:------------- 此时的maxLen[][]:

image.png image.png

开始上下左右走:

(1)向上

没有出界并且高度是向下的,到这一步

image.png

变为maxLen[3][3] = max(dfs(2,3) + 1, 1)

而dfs(2,3) 为多少呢?

按照这个步骤:

image.png

可知,直接返回maxLen[2][3],为1;

所以maxLen[3][3] = max(2,1);为2

2是什么意思呢?

是[3][3]->[2][3]这条路径的长度!

这里是不是就清晰一点了

image.png

ok,向上完成了,最长的只有一条路径长度为2的。

矩阵:------------- 此时的maxLen[][]:

image.png image.png

(2)向右

右边是0,说明没走过令它等于1

矩阵:------------- 此时的maxLen[][]:

image.png image.png

然后计算一下dfs(3,4):

也是分四个方向,这里就简略写了:

向上1,向右2,向下1,向左1

矩阵:------------- 此时的maxLen[][]:

image.png image.png

这时候

dfs(3,3 )= max(dfs(3,4)+1,maxLen[3][3])

=max(3,2)=3

就变为:

矩阵:------------- 此时的maxLen[][]:

image.png image.png

ok,向右完成了

(3)向下

矩阵:------------- 此时的maxLen[][]:

image.png image.png

(4)向左

矩阵:------------- 此时的maxLen[][]:

image.png image.png

接下来就继续遍历,结束的样子就是:

矩阵:------------- 此时的maxLen[][]:

image.png image.png

这里只是巧合!左右两张图一样,把[3][3]的点高度变为999右边maxLen图也是这么画!

找出最大值

image.png

这个函数就是每遍历一个点,有一个dfs出来的值比现在的dis大就换dis。

最后,源码:

#include<iostream>
using namespace std;
int to[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int R, C, high[100][100], maxLen[100][100];

int dfs(int x, int y) {
	if (maxLen[x][y] != 0)
		return maxLen[x][y];

	maxLen[x][y] = 1;
	for(int i = 0; i <= 4; i++) {
		int x1 = x + to[i][0];
		int y1 = y + to[i][1];
		//不出界并且是往低处走 
		if( x1 >= 1 && y1 >= 1 && x1 <= R && y1 <= C && high[x1][y1] < high[x][y]) {
			maxLen[x][y] = max(dfs(x1, y1) + 1, maxLen[x][y]);
		}
	}
	return maxLen[x][y];
}
int main() {
	cin >> R >> C;
	int dis = 1;
	for(int i = 1; i <= R; i++) {
		for(int j = 1; j <= C; j++) {
			cin >> high[i][j];
			maxLen[i][j] = 0;
		}
	}
	for(int i = 1; i <= R; i++) {
		for(int j = 1; j <= C; j++) {
			dis = max(dis, dfs(i, j));
		}
	}
	cout << dis << endl;
	return 0;
}

完结

image.png