结合滑雪讨论DFS和记忆化搜索问题
2021-04-18 00:22:38
DFS(深度优先搜索):
关于DFS的定义概念介绍参看:深度优先搜索
简单来说,DFS可以理解为深度优先的递归加回溯。
下面看题:洛谷P1434
题目描述
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 更长。事实上,这是最长的一条。
输入格式
输入的第一行为表示区域的二维数组的行数 RR 和列数 CC。下面是 RR 行,每行有 CC 个数,代表高度(两个数字之间用 11 个空格间隔)。
输出格式
输出区域中最长滑坡的长度。
输入输出样例
输入 #15 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输出 #125说明/提示
对于 100\%100% 的数据,1\leq R,C\leq 1001≤R,C≤100。
第一思路:
首先想到枚举每一个点的可能最长路径,在这里需要用到DFS,故可写出dfs函数如下:
int dfs(int x, int y) { int ans2 = 0; for (int i = 0; i < 4; i++) { int q = x + dic[i][0];//dic为方向变量控制上下左右 int t = y + dic[i][1]; if (q >= 0 && t >= 0 && q < R && t < C && a[q][t] < a[x][y]) { ans2 = max(ans2, dfs(q, t)); } } return ans2+1; }
但食用后发现会TLE,这是因为每一个点可能被重复多次循环记录到,每一次for循环都会重复计算,而如果能设置一个变量使之直接表示该点所能达到的最长路径,就可以省去许多时间。这就有了第二种思路,记忆化搜索.
第二思路:
记忆化搜索:记忆化搜索的思想是,在搜索过程中,会有很多重复计算,如果我们能记录一些状态的答案,就可以减少重复搜索量
因此我们设置一个二维数组dp[x][y]来表示在点(x,y)处所能达到的最长路径。
代码如下:
int dfs(int x, int y) { if (dp[x][y]) return dp[x][y];//如果dp不为0,证明该点已经被计算过了,直接返回该点的值即可。 dp[x][y] = 1;//某个点最短也是1,为了和0区分判断是否被计算过 for (int i = 0; i < 4; i++) { int q = x + dic[i][0]; int t = y + dic[i][1]; if (q >= 0 && t >= 0 && q < R & t < C && a[q][t] < a[x][y]) { dfs(q, t); dp[x][y] = max(dp[x][y], dp[q][t] + 1); } } return dp[x][y]; }
主函数部分:
int main() { cin >> R >> C; for (int i = 0; i < R; i++) { for (int j = 0; j < C; j++) { cin >> a[i][j]; } } for (int x = 0; x < R; x++) { for (int y = 0; y < C; y++) { ans = max(ans, dfs(x, y)); } } cout << ans; return 0; }
未完待续,后续仍会补充......

浙公网安备 33010602011771号