动态规划-Help JimmyV2

完成的游戏:场景中包括多个长度和高度各不相同的平台。地面是最低的平台,高度为零,长度无限。
Jimmy老鼠在时刻0从高于所有平台的某处开始下落,它的下落速度始终为1米/秒。当Jimmy
落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒。当Jimmy
跑到平台的边缘时,开始继续下落。Jimmy每次下落的高度不能超过MAX米,不然就会摔死,
游戏也会结束。设计一个程序,计算Jimmy到地面时可能的最早时间。

输入数据
第一行是测试数据的组数t(0 <= t <= 20)。每组测试数据的第一行是
四个整数N,X,Y,MAX,用空格分隔。N是平台的数目(不包括地面),
X和Y是Jimmy开始下落的位置的横竖坐标,MAX是一次下落的最大高度。接
下来的N行每行描述一个平台,包括三个整数,X1[i],X2[i]和H[i]。H[i]表示
平台的高度,X1[i]和X2[i]表示平台左右端点的横坐标。1 <= N <= 1000,
-20000 <= X, X1[i], X2[i] <= 20000,0 < H[i] < Y <= 20000(i = 1..N)。
所有坐标的单位都是米。
Jimmy的大小和平台的厚度均忽略不计。如果Jimmy恰好落在某个平台的
边缘,被视为落在平台上。所有的平台均不重叠或相连。测试数据保Jimmy
一定能安全到达地面。

输出要求:对输入的每组测试数据,输出一个整数,Jimmy到地面时可能的最早时间。
输入样例
1
3 8 17 20
0 10 8
0 10 13
4 14 3
输出样例
23


思路:递归实现
求到达地面的最短时间,将初始位置看作一个平台,地面也看作一个平台,
对各个平台的高度进行排序,用递归来做用最大的一直往下找到地位的最短时间
为了提高效率,利用leftMinList, rightMinList两个列表分别记录平台
左右方向下落的最小时间

python算法实现:
 1 # 二维列表的列索引含义:0表示平台左边坐标、1表示平台右边坐标、2表示平台的高度
 2 plat_list = []
 3 # 递归中为了避免重复计算,提高运算效率,需存储每个i平台左右下落的最小时间
 4 # 存储i平台左右下落的最小时间,-1表示没有计算过,
 5 leftMinList, rightMinList = [], []
 6 # 定义无穷大
 7 inf = float('inf')
 8 N, MaxHeight = 0, 0
 9 
10 
11 # 计算从平台i到地面的最短时间,往左往右都需要计算才能找到最小值
12 # jimmy从出发下落到第1块板有可能走左边也可能走右边
13 # N表示平台的个数
14 def minDropTime(i, isGoLeft):
15     global plat_list, N, MaxHeight, leftMinList, rightMinList
16     x = 0
17     y = plat_list[i][2]  # 当前点的高度
18     # 如果是去左边,就走到左边边上,如果去右边,就走到右边边上
19     if isGoLeft:
20         x = plat_list[i][0]
21     else:
22         x = plat_list[i][1]
23     # 查找如果从左边或者右边下落,是否能到达下一块板
24     # k记录可以下落板的编号
25     k = 0
26     for j in range(i + 1, N + 1):
27         # 如果x落在下一块板的中间,则说明可以从i下落到j板
28         if plat_list[j][0] <= x <= plat_list[j][1]:
29             k = j
30             break
31     # 说明往i下面没有板可以下落
32     if k == 0:
33         if y > MaxHeight:
34             return inf
35         else:
36             return y
37     else:  # 有可以下落的板
38         if y - plat_list[k][2] > MaxHeight:
39             return inf
40         else:
41             # =-1,说明该平台下落的最小时间没有计算过
42             if leftMinList[k] == -1:
43                 leftMinList[k] = minDropTime(k, True)
44             if rightMinList[k] == -1:
45                 rightMinList[k] = minDropTime(k, False)
46             # 如果计算过k平台下落的最小时间,则可以直接计算,不需要重新递归提高效率
47             # 返回平台i往左或者右方向下落的最小值=高度差+min(走k平台左端最小时间,走k平台右端最小时间)
48             return (y - plat_list[k][2]) + min(x - plat_list[k][0] + leftMinList[k],
49                                                plat_list[k][1] - x + rightMinList[k])
50 
51 
52 def main():
53     global plat_list, N, MaxHeight, leftMinList, rightMinList
54     # t表示测试数据的组数
55     t = int(input())
56     while t > 0:
57         # N: 平台数目 X, Y: 开始下落位置坐标 MAX: 一次下落最大高度
58         N, X, Y, MaxHeight = 0, 0, 0, 0
59         N, X, Y, MaxHeight = map(int, input().split())
60         # 记录从该平台左边下落的最小时间
61         leftMinList = [-1 for i in range(N + 1)]
62         # 记录从该平台右边下落的最小时间
63         rightMinList = [-1 for i in range(N + 1)]
64         # 平台的二维数组列表
65         plat_list = [[0 for i in range(3)] for i in range(N + 1)]
66 
67         # 把jimmy的出发点也当做一个平台,即递归的出发点
68         plat_list[0][0], plat_list[0][1], plat_list[0][2] = X, X, Y
69         for i in range(1, N + 1):
70             plat_list[i] = [int(n) for n in input().split()]  # 输入各平台参数
71         # 对平台按高度排序,sorted这个函数要重新覆盖原来的列表内容才会排序
72         plat_list = sorted(plat_list, key=(lambda x: x[2]), reverse=True)
73         # [[8, 8, 17], [0, 10, 13], [0, 10, 8], [4, 14, 3]]
74         min_value = minDropTime(0, True)
75         print("Jimmy到底地面时可能的最早时间为:%d" % min_value)
76         t = t - 1
77 
78 
79 if __name__ == '__main__':
80     main()
 
原文地址:https://www.cnblogs.com/an-wl/p/13056079.html