二维DP—记忆化搜索—洛—滑雪
P1434 [SHOI2002] 滑雪
题目描述
Michael 喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael 想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:
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
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 \(24-17-16-1\)(从 \(24\) 开始,在 \(1\) 结束)。当然 \(25-24-23-\ldots-3-2-1\) 更长。事实上,这是最长的一条。
输入格式
输入的第一行为表示区域的二维数组的行数 \(R\) 和列数 \(C\)。下面是 \(R\) 行,每行有 \(C\) 个数,代表高度(两个数字之间用 \(1\) 个空格间隔)。
输出格式
输出区域中最长滑坡的长度。
输入输出样例 #1
输入 #1
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
输出 #1
25
说明/提示
对于 \(100\%\) 的数据,\(1\leq R,C\leq 100\)。
对于任意输入的高度 \(h\),满足 \(0 \le h \le 10000\),且 \(h\) 是整数。
做法一:BFS + 动态规划
想法:从每个点出发,看看能不能跟新周围的点,能跟新的话入队。自上向下。
注意:初始时要把每个点都入队,不能只考虑刚开始只从最高点开始跟新,因为最长路径不一定包括最高点。且每个点的dp初始值都为1。
代码:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int r,c,ans;
int m[105][105],dp[105][105];
bool vis[105][105]; //防止重复入队
struct ty
{
int x,y;
};
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
queue <ty> q;
int main()
{
cin>>r>>c;
int temp = 0;
for(int i = 1;i <= r;i++)
{
for(int j = 1;j <= c;j++)
{
cin>>m[i][j];
dp[i][j] = 1;
q.push({j,i});
vis[i][j] = true;
}
}
while(!q.empty())
{
ty temp = q.front();
q.pop();
int x1 = temp.x, y1 = temp.y;
vis[y1][x1] = false;
for(int i = 0;i < 4;i++)
{
int dx = x1 + dir[i][0];
int dy = y1 + dir[i][1];
if(dx < 1 || dx > c || dy < 1 || dy > r || m[dy][dx] >= m[y1][x1]) continue;
if(dp[y1][x1] + 1 > dp[dy][dx])
{
dp[dy][dx] = dp[y1][x1] + 1;
if(!vis[dy][dx])
{
q.push({dx,dy});
vis[dy][dx] = true;
}
}
}
}
for(int i = 1;i <= r;i++)
{
for(int j = 1;j <= c;j++) ans = max(ans,dp[i][j]);
}
cout<<ans;
return 0;
}
做法二:DSF + 动态规划 + 记忆化搜索
想法:常规的二维动态规划都是有一定的顺序,像每行每列的遍历,这里想要这样就必须得dfs递推到最终状态。自下向上。代码更简单,但要注意栈溢出,赋初值,终止搜索,记忆化实现等问题。
代码:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
int r,c,ans;
int m[105][105],dp[105][105];
int dir[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};
int dfs(int x,int y)
{
if(dp[y][x]) return dp[y][x]; //核心:体现记忆化搜索,保证每个点只搜一遍
for(int i = 0;i < 4;i++)
{
int dx = x + dir[i][0];
int dy = y + dir[i][1];
if(dx < 1 || dx > c || dy < 1 || dy > r || m[dy][dx] <= m[y][x]) continue;
dp[y][x] = max(dp[y][x], dfs(dx,dy)+1);
}
return dp[y][x] = max(dp[y][x] , 1); //终止记忆化,最高点只有自己一个点,不能再跟新。等号是从右往左赋值
}
int main()
{
cin>>r>>c;
int temp = 0;
for(int i = 1;i <= r;i++)
{
for(int j = 1;j <= c;j++)
{
cin>>m[i][j];
}
}
for(int i = 1;i <= r;i++)
for(int j = 1;j <= c;j++) dfs(j,i);
for(int i = 1;i <= r;i++)
{
for(int j = 1;j <= c;j++) ans = max(ans,dp[i][j]);
}
cout<<ans;
return 0;
}

浙公网安备 33010602011771号