题意

  • 在n*m的地图中,每个点有权值,并且在任一点都可以向四周比自己权值小的点走动,求最多走动多少步

思路

  • 对于走动最长路径的最后一个点,他一定是由上下左右中比他小且已走路径最长的点走来,对于倒数第二个点同理,故需要维护每个点可以走的最长路径,记dp[i][j]为从(i,j)开始走的最长路径,dp[i][j]=max(上下左右权值比他小的值的最长路径+1)
  • 需要注意的是,维护状态转移方程的同时,需要先将每个走到的点最短路径初始化为1,即至少可以走自己这一步,以保证使用记忆化搜索时,走到权值最小的点也能正确维护
  • 本题如果使用递推的话,总需要从地图中权值最小的点开始按升序维护,等价于,可能会超时

AC代码

#include<bits/stdc++.h>
using namespace std;

const int N=120;
int dir[4][2]={1,0,-1,0,0,1,0,-1};
int mp[N][N];
int dp[N][N];
int n,m;
int deal (int x,int y){
    if(x<1||y<1||x>n||y>m)return 0;
    if(dp[x][y]!=0)return dp[x][y];
    dp[x][y]=1;
    for(int i=0;i<4;i++){
        int tx=x+dir[i][0];
        int ty=y+dir[i][1];
        if(mp[tx][ty]<mp[x][y]) dp[x][y]=max(deal(tx,ty)+1,dp[x][y]);   
    }
    return dp[x][y];
}
int main(){
    cin >> n >> m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin >> mp[i][j];            
        }
    }    
    int ans=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            ans=max( ans , deal(i,j) );
        }
    }
    cout << ans <<endl;
    return 0;
}