题目
看了好久才看懂题目,下面是原题的回忆:
有一个取货机器可以在各个巷道间来回移动,同一个巷道里取货不用移动,只需要伸机械臂(所以移动是一维的)。告诉你机器此时在哪条巷道(初始位置),告诉你这个机器要取哪些货物(K种货物),每种货物取多少个(长度为K的数组),再告诉你每个巷道里各种货物的数量(KxN的矩阵,N条巷道)。最后问取完这些货物需要移动的最短距离
思路
设想远处的巷道有许多货物,那么只要走到那里吃一口就能把清单清掉。但是走的过程中吃路途中的货物是不费时间的,所以说还不如先把近的货物吃掉。递归地从初始位置开始,由近到远地搜索,返回所有成功取完货物的移动步数,最后取最小值,这也许是个不错的方法,关键点是记录步数和已搜索过的范围,再范围之外搜索。
代码
initpos = 2
M = [0,0,0,0,0,0,1]
inventory = [
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1],
]
# 取pos巷道的货物
def drop(pos, M):
for i in range(len(M)):
M[i] -= inventory[i][pos]
# 还原M
def plus(pos, M):
for i in range(len(M)):
M[i] += inventory[i][pos]
# 找最短移动距离,left, right指示已经搜索过的范围,
# step记录移动步数,pos为当前搜索位置
def find(pos, M, step, left, right):
# 搜索位置超出范围结束递归
if pos < 0 or pos >= len(inventory[0]):
return -1
drop(pos, M)
if max(M) <= 0: # 若清单的货物都取够了个,返回步数
plus(pos, M)
return step
# 初始状态,向左一格或向右一格搜索
if pos == left and pos == right:
result1 = find(left-1, M, step+1, left-1, right)
result2 = find(right+1, M, step+1, left, right+1)
# 若当前位置在查找过的范围左边缘,向左跳一格,
# 或跳到右边缘右边一格(移动right+1-pos步)
elif pos == left:
result1 = find(left-1, M, step+1, left-1, right)
result2 = find(right+1, M, step+(right+1-pos), left, right+1)
# 若当前位置在查找过的范围右边缘,
# 向右跳一格或跳到左边缘左边一格(移动pos-(left-1)步)
elif pos == right:
result1 = find(right+1, M, step+1, left, right+1)
result2 = find(left-1, M, step+(pos-(left-1)), left-1, right)
else:
raise Exception
plus(pos, M) # 退出递归前要把M还原,避免干扰别的递归步骤
# 我这里超出范围的情况result为负数,所以只比较正数的最小值
if result1 >= 0 and result2 >= 0:
return min(result1, result2)
elif result1 >= 0:
return result1
elif result2 >= 0:
return result2
else:
return -1
print(find(initpos, M, 0, initpos, initpos))
本解法仅供参考,这是我后来想的解法,当时答的时候写了很多错误