动态规划-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()