动态规划——记忆化搜索以滑雪问题为例

记忆化搜索

记忆化搜索=搜索的形式+动态规划的思想

  1. 概述
    一般说来,动态规划总要遍历所有的状态,而搜索可以排除一些无效状态。更重要的是搜索还可以剪枝,可能剪去大量不必要的状态,因此在空间开销上往往比动态规划要低很多。记忆化算法在求解的时候还是按着自顶向下的顺序,但是每求解一个状态,就将它的解保存下来,以后再次遇到这个状态的时候,就不必重新求解了。这种方法综合了搜索和动态规划两方面的优点,因而还是很有实用价值的。
  2. 一般思路

通过动态规划的分析方法,得到状态定义、状态转移方程、状态初始化等信息,自顶而下的思考算法实现方式

模板

st=[[-1] * N for _ in range(N)]
def dfs(i, j) :
	if st[i][j] != -1 : #说明(i,j)已经被计算过了可以直接使用
		return st[i][j]
	if i > 0 or i < n or j > 0 or j < n or i < j or ...:#边界条件防止越界或破坏题目条件
		return 0或者INF...
	st[i][j] = 0...依据题意初始化st[i][j]
	if 一些条件 :
		st[i][j] = dfs(i + X, j + X) +... # 状态转移方程
	else :
		st[i][j] = ....
	#在这里可以处理题目逻辑
	return st[i][j] 
	

例题

给定一个 R 行 C 列的矩阵,表示一个矩形网格滑雪场。

矩阵中第 i 行第 j 列的点表示滑雪场的第 i 行第 j 列区域的高度。

一个人从滑雪场中的某个区域内出发,每次可以向上下左右任意一个方向滑动一个单位距离。

当然,一个人能够滑动到某相邻区域的前提是该区域的高度低于自己目前所在区域的高度。

下面给出一个矩阵作为例子:

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−2−1。

在给定矩阵中,最长的滑行轨迹为 25−24−23−…−3−2−1,沿途共经过 25 个区域。

现在给定你一个二维矩阵表示滑雪场各区域的高度,请你找出在该滑雪场中能够完成的最长滑雪轨迹,并输出其长度(可经过最大区域数)。

输入格式
第一行包含两个整数 R 和 C。

接下来 R 行,每行包含 C 个整数,表示完整的二维矩阵。

输出格式
输出一个整数,表示可完成的最长滑雪长度。

数据范围
1≤R,C≤300,
0≤矩阵中整数≤10000
输入样例:
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
输出样例:
25

动态规划
Syntax error in textmermaid version 10.9.0

可以得到状态转移方程为
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i ] [ j + 1 ] , f [ i + 1 ] [ j ] , f [ i ] [ j − 1 ] ) + 1 f[i][j] = max(f[i - 1][j], f[i][j + 1], f[i + 1][j], f[i][j - 1]) + 1 f[i][j]=max(f[i1][j],f[i][j+1],f[i+1][j],f[i][j1])+1

DFS设计

初始化 f [ i ] [ j ] f[i][j] f[i][j]为-1,代表当前状态未被求解,当遍历时,将其赋值为1

N = 310
DIRC = [[-1, 0], [0, 1], [1, 0], [0, -1]]

h = [[0] * N for _ in range(N)]
f = [[-1] * N for _ in range(N)]

def dp(a, b) :
	if f[a][b] != -1 :
		return f[a][b]
	
	f[a][b] = 1
	for i in DIRC :
		x, y = a + i[0], b + i[1]
		if 1 <= x <= n and 1 <= y <= m and h[a][b] > h[x][y] :
			f[a][b] = max(f[a][b], dp(x, y) + 1)
	return f[a][b]

n, m = map(int , input().split())

for i in range(1, n + 1) :
	h[i][1 : m + 1] = list(map(int , input().split()))

res = 0
for i in range(1, n + 1) :
	for j in range(1, m + 1) :
		res = max(res, dp(i, j))

print(res)

总结

记忆化搜索内容上是动态规划思想,实现形式是搜索。好处在于一方面解决了暴搜时间复杂度过高的问题,另一方面解决了动态规划遍历顺序难以确定的问题,妙啊!!

posted @   chanxe  阅读(105)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示