Longest Run on a Snowboard题解

最近忙于工程项目设计,算法落下了一点,碰巧近期在学动态规划算法,很有用,同时有很具有思考性,还是重新回顾了动规和记忆化搜索的经典题目Longest Run on a Snowboard(有的oj又名曰Skiing),

题面

在这里插入图片描述
在这里插入图片描述

大致的题意就是在一个二维地图中找出一条最长严格下降路径,很显然,这就是一道搜索算法题。

思路启示

想要在这么一个二维地图中找到所需路径,单从一个点出发肯定是不够的,必须尝试从二维地图中的每个点出发,dfs到一条最长路径,每个点遍历过程中更新路径的最大值。然而,要是真的只是这么做的话,就很愉快地TLE了。为什么呢?

核心——记忆化搜索

问题很明显,对同一个格点,有可能进行了重复性的工作(可以自己模拟一下,就知道哪儿重复了)。对于一个格点,其路径最大值是固定的,一旦确定下来,以后就不会改变,需要用到的时候直接拿过来用(有点像…动归中的无后效性??暂且可以这么理解)。这么一来,开一个dp数组来记录其值不就能够做到“剪枝”了?

动态规划思想

在思考动态规划问题的时候,我们的思维不是跳跃的,而是着眼当下,重点思考当前问题与子问题的关系。拿本题来说,对于格点(x,y),其最长路径的来源无非就是上下左右4个方向加1。把当前问题想好了,由于问题具有最有子结构(重叠子问题)的性质,接下去的解法与当前都是一样的,只是规模变小。

C++代码实现(55行)

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define N 102
using namespace std;
int n,m;
int a[N][N];
int dp[N][N];
int nxt[][2] = {{-1,0}, {0,1}, {1,0}, {0,-1} };

inline bool check(int x, int y) {
    return x >= 1 && y >= 1 && x <= n && y <= m;
}

int dfs(int x, int y) {
    int tmp = 0;
    for (int i = 0; i < 4; i++) {
        int tx = x + nxt[i][0];
        int ty = y + nxt[i][1];
        if (check(tx,ty) && a[tx][ty] < a[x][y] ) {
            if (dp[tx][ty] != -1) {
                tmp = max(dp[tx][ty]+1,tmp);
            } else {
                int c = dfs(tx,ty);
                tmp = max(c+1,tmp);
                dp[tx][ty] = c;
            }
        }
    }
    return dp[x][y] = tmp;
}

int main() {
    int t; cin >>t;
    while(t--) {
        memset(dp,-1,sizeof(dp));
        string name;
        cin >> name;
        cin >> n >> m;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                scanf("%d",&a[i][j]);
            }
        }
        int ans = -1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                ans = max(ans,dfs(i,j));
            }
        }
        cout << name << ":" << " " << ans+1 << "\n";
    }
    return 0;
}

后记

如果您对算法与数据结构感兴趣,欢迎关注我的公众小号(ACMFans Club)和我交流,公众号上面也放了一些我的个人小项目(虽然目前不会很多),涵盖Java网络编程,Python爬虫,Qt编程,Web前端…
鉴于经典题目的流传性,以后我会在公众号更新的时候同时更新我的CSDN博客。
在这里插入图片描述

时隔2个月,再度回归算法,谨此。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值