滑雪问题(记忆化搜索)

注:由于本题有多种不同版本,这里统一用XXX和YYY代替不同的专有名词

【问题描述】

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

区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:示例

XXX可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。在上面的例子中,一条可滑行的滑坡为24-17-16-1。当然25-24-23-…-3-2-1更长。事实上,这是最长的一条。

【输入格式】

输入的第一行表示区域的行数R和列数C(1 <= R,C <= 500)。下面是R行,每行有C个整数,代表高度h,0<=h<=10000。

【输出格式】

输出最长区域的长度。

【输入输出样例 1】

input

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

output

25

时间限制:2s
空间限制:128MB


题解

本题的测试数据有着一定的误导性,有些人在开始会直接出现两个错误思路:

  1. 从单个或多个最高点开始的路径一定最长
  2. 每次选择与当前点落差最小的点作为下一个点的路径一定最长
  3. 前两种思路全部出现

这三种情况实际上只要稍稍想一想就能发现反例,就看你能否仔细思考反问了

正解:记忆化搜索

爆搜思路:将每个点作为起始点,向四个方向中合法的点试最长路径
这样有多层嵌套循环的题目,单纯的爆搜基本上都会爆时间 有空可以算一下
所以需要在DFS时带上记忆化,用全局数组记录每个点自身为起始点时的最长路径,需要时直接取用
更详细请看下面代码与注释↓

#include<bits/stdc++.h>
using namespace std;
typedef struct node
{
   
	int h,path;//h:此点的高度,path:以该点为起始点时的最长路径
}NODE,*PNODE;
NODE a[
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
滑雪问题是一个经典的算法问题,其主要思路是通过动态规划的方式求解最长下降路径。 在C语言中,可以使用二维数组存储滑雪场地形高度信息,然后通过动态规划算法求解最长下降路径。 具体实现步骤如下: 1. 定义二维数组存储滑雪场的高度信息: ```c int height[N][N]; ``` 其中N是滑雪场的大小,可以根据实际情况进行调整。 2. 初始化高度信息: ```c for(int i = 0; i < N; i++){ for(int j = 0; j < N; j++){ scanf("%d", &height[i][j]); } } ``` 3. 定义一个二维数组dp,dp[i][j]表示从(i,j)位置开始的最长下降路径长度: ```c int dp[N][N]; ``` 4. 初始化dp数组: ```c int max_len = 0; for(int i = 0; i < N; i++){ for(int j = 0; j < N; j++){ dp[i][j] = -1; } } for(int i = 0; i < N; i++){ for(int j = 0; j < N; j++){ max_len = max(max_len, dfs(height, dp, i, j)); } } ``` 其中,dfs函数用于计算从(i,j)位置开始的最长下降路径长度。 5. 实现dfs函数: ```c int dfs(int height[][N], int dp[][N], int i, int j){ if(dp[i][j] != -1){ return dp[i][j]; } int max_len = 1; int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}}; for(int k = 0; k < 4; k++){ int nx = i + dir[k][0]; int ny = j + dir[k][1]; if(nx < 0 || nx >= N || ny < 0 || ny >= N){ continue; } if(height[nx][ny] >= height[i][j]){ continue; } max_len = max(max_len, 1 + dfs(height, dp, nx, ny)); } dp[i][j] = max_len; return max_len; } ``` 6. 计算最长下降路径长度: ```c printf("%d\n", max_len); ``` 完整代码如下: ```c #include <stdio.h> #define N 1001 int max(int a, int b){ return a > b ? a : b; } int dfs(int height[][N], int dp[][N], int i, int j){ if(dp[i][j] != -1){ return dp[i][j]; } int max_len = 1; int dir[4][2] = {{-1,0},{1,0},{0,-1},{0,1}}; for(int k = 0; k < 4; k++){ int nx = i + dir[k][0]; int ny = j + dir[k][1]; if(nx < 0 || nx >= N || ny < 0 || ny >= N){ continue; } if(height[nx][ny] >= height[i][j]){ continue; } max_len = max(max_len, 1 + dfs(height, dp, nx, ny)); } dp[i][j] = max_len; return max_len; } int main(){ int height[N][N]; int dp[N][N]; int max_len = 0; for(int i = 0; i < N; i++){ for(int j = 0; j < N; j++){ dp[i][j] = -1; } } int n; scanf("%d", &n); for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ scanf("%d", &height[i][j]); } } for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ max_len = max(max_len, dfs(height, dp, i, j)); } } printf("%d\n", max_len); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值