先看题目:https://ac.nowcoder.com/acm/problem/105685
题目描述:
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小。任选一点作为起点,问最长滑雪区域的长度。
解题思路:
动态规划入门题,结合此题回顾一下动态规划的一般步骤。
first ,首先结合原问题和子问题确定状态(我是谁,我在哪)
题目在求什么?要求出这个值,我们需要知道什么?什么是影响答案的因素?
(一维描述不完就二维,二维描述不完就三维四维)
这道题状态是显然要描述位置的,定义dp[i][j]为人从坐标(i,j)出发可以最长滑多远。
second , 确定转移方程(我从哪里来,我到哪里去)
检查参数是否足够,分情况:(最后一次操作,取不取,怎么样取,前一项是什么?)
初始边界是什么。还有要注意无后效性,比如说求A要求B,求B要求C,求C要求A,这就不符合无后效性了。
这道题,从起点,人可以向四个方向中高度小于h的坐标走,故状态转移方程
dp[i][j] = max{dp[i+dir][j+dir]} (h[i+dir][j+dir] < h[i][j])
third , 确定编程实现方式
递推 or 记忆化搜索
这道题的话递推不太方便,可以使用记忆化搜索。
代码:
#include<bits/stdc++.h> using namespace std; int r, c; int h[10010][10010]; int dp[10010][10010]; int vis[10010][10010]; int dir[4][2]={0,1,0,-1,1,0,-1,0}; int dfs(int x, int y) { if(vis[x][y]) return dp[x][y]; vis[x][y]=1; for(int k = 0; k < 4; k++) { int dx = x+dir[k][0]; int dy = y+dir[k][1]; if(dx < 0 || dx >= r || dy < 0 || dy >= c) continue; if(h[dx][dy] >= h[x][y]) continue; dp[x][y] = max(dp[x][y], dfs(dx, dy)+1); } return dp[x][y]; } int main() { scanf("%d%d",&r,&c); for(int i = 0; i < r; i++) for(int j = 0; j < c; j++) { scanf("%d",&h[i][j]); dp[i][j] = 1; } int ans = 0; for(int i = 0; i < r; i++) for(int j = 0; j < c; j++) { ans = max(ans, dfs(i, j)); } printf("%d\n", ans); }