滑雪

| DFS | 递归 |DP|

此题有两种方式,一种为递归,一种为非递归的写法。我一开始用的是非递归的写法,就需要从最低点开始更新dp才不会出现要更新较高点时无法利用旁边较低点的dp数据。这样的代码长度较为冗长,且对空间利用率不高。

#include<iostream>
#include<algorithm>

using namespace std;

int m,n;
//m代表行,n代表列
struct pos{
    int x;
    int y;
    int h;
};

pos p[10010];
int cnt = 0;
int h[110][110];
int dp[110][110];

int dx[] = {0,1,0,-1};
int dy[] = {1,0,-1,0};

bool is_valid(int x,int y,int cur_h){
    if(x>=0&&x<=m-1&&y>=0&&y<=n-1&&h[x][y]<cur_h){
        return true;
    }
    return false;
}

bool cmp(pos a,pos b){
    return a.h<b.h;
}

int main(){
    cin>>m>>n;
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            pos temp;
            cin>>h[i][j];
            temp.h = h[i][j];
            temp.x = i;
            temp.y = j;
            p[cnt++] = temp;
            dp[i][j] = -1;
        }
    }
    //还没标记的dp用-1,这样可以避免之后的计算错误
    sort(p,p+cnt,cmp);
    dp[p[0].x][p[0].y] = 1;
    for(int i=1;i<cnt;i++){
        int cur_x = p[i].x;
        int cur_y = p[i].y;
        int m_path = 1;
        for(int k=0;k<4;k++){
            int nx = cur_x+dx[k];
            int ny = cur_y+dy[k];
            if(is_valid(nx,ny,p[i].h)){
                if(dp[nx][ny]+1>m_path){
                    m_path = dp[nx][ny]+1;
                }
            }
        }
        dp[cur_x][cur_y] = m_path;
    }
    int m_lenth = 1;
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            if(m_lenth<dp[i][j]){
                m_lenth = dp[i][j];
            }
        }
    }
    cout<<m_lenth<<endl;
    return 0;
}

另一种方法是递归的写法。递归可以解决如何保证更新某点旁边已经更新正确的dp值,即:

dfs(高点) {
    需要 dfs(低点)  // 👈 递归会先去算低点
    // 等低点算完才继续
}

总的代码为:

#include <iostream>
#include <cstring>
using namespace std;

int m, n;
int h[110][110];
int dp[110][110];
int dx[] = {0, 1, 0, -1};
int dy[] = {1, 0, -1, 0};

int dfs(int x, int y) {
    // 如果已经计算过,直接返回
    if (dp[x][y] != -1) return dp[x][y];
    
    dp[x][y] = 1;  // 当前点至少长度为1
    
    // 尝试四个方向
    for (int k = 0; k < 4; k++) {
        int nx = x + dx[k];
        int ny = y + dy[k];
        
        // 检查边界和高度条件
        if (nx >= 0 && nx < m && ny >= 0 && ny < n && h[nx][ny] < h[x][y]) {
            dp[x][y] = max(dp[x][y], dfs(nx, ny) + 1);
        }
    }
    
    return dp[x][y];
}

int main() {
    cin >> m >> n;
    
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            cin >> h[i][j];
        }
    }
    
    // 初始化dp数组
    memset(dp, -1, sizeof(dp));
    
    int maxLen = 1;
    
    // 从每个点开始搜索
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            maxLen = max(maxLen, dfs(i, j));
        }
    }
    
    cout << maxLen << endl;
    
    return 0;
}

通过此题,借助Claude的一句话:递归的本质是自相似性即把一个大问题拆成具有相同结构的小问题,此题的dfs就是如此:与以往不同的是,此处的dfs不再仅是用于深度优先搜索的无意义量,此处的dfs就是代表从坐标(x,y)处出发的路径最大值。注:此处代码中的dp仅仅用来记忆结果,无动态规划的算法思维。

posted @ 2025-11-25 20:54  channy_zheng  阅读(5)  评论(0)    收藏  举报