问题描述
问题
假设你有一个像这样的 m * n 矩阵:
Grid = 4 * 4
1 1 1 1
2 2 2 2
3 3 3 3
4 4 4 4
你想从左上角连接到右下角,你只能向右或向下。此外,您还想找到获得所需总和所需的操作。
例如:
在教科书中找到的脚本,不清楚
def move(m,n,sum):
count = m + n - 1
max_val = m
s = sum
r = []
while max_val > 0:
if count <= 0:
return False,r
least = max_val * ((max_val - 1) / 2)
r.append(max_val)
s -= max_val
count -= 1
while ((count > 0) and (s > least + (count - (max_val - 1)) * (max_val - 1))):
r.append(max_val)
s -= max_val
count -= 1
if s < least:
return False,r
max_val -= 1
return True,r
def combine(m,sum):
result,new_res = move(m,sum)
new_res.reverse()
for i in range(1,len(new_res)):
if new_res[i] == new_res[i - 1]:
print("R")
else:
print("D")
combine(4,4,16)
我不太明白解决方案。
有人能解释一下算法吗?
特别是在函数 move 中,它在 while 循环中执行此检查:
while ((count > 0) and (s > least + (count - (max_val - 1)) * (max_val - 1))):
问题
- 这个算法的名称是什么?
- 这个脚本是如何工作的?
- 运行时间(时间复杂度)是多少?
谢谢!
解决方法
所以脚本写得不好,也没有遵循最佳实践,不得不说我重新调整了它,希望更清晰
源代码
注意:我已经添加到我的 GitHub Algorithm-Complete-Guide 中,它正在建设中,请随意使用
def move(m,n,weight_limit):
# ==== < CONFIG VARIABLES > ==== #
step_counter = m + n - 1
max_val = m # NOTE: It starts from the last Value (4) and Goes Backwards
path = [] # NOTE: Stores the path (need to reverse it afterwards)
while max_val:
if step_counter <= 0: # NOTE: starting Node so it break Not need to return
break
least = max_val * ((max_val - 1) / 2)
path.append(max_val)
weight_limit -= max_val
step_counter -= 1
if weight_limit < least: # NOTE: Moved it up here because makes more sense to check this first and break
break
# ==== < ROW CHECK | CAN IT GO TO THE LEFT? > ==== #
if step_counter: # NOTE: Moved it as makes it more clear
check_row = least + (step_counter - (max_val - 1)) * (max_val - 1)
while weight_limit > check_row: # FAQ: 1 Footnotes
path.append(max_val)
weight_limit -= max_val
step_counter -= 1
max_val -= 1
return path
def combine(m,sum):
path = move(m,sum)
path.reverse() # NOTE: Reverse the result Path
result = []
for i in range(1,len(path)):
if path[i] == path[i - 1]: # NOTE: Check if next Value is the same then it moved it to the Right
result.append((path[i],'Right'))
else:
result.append((path[i],'Left'))
return result
def prettify_result(res):
for value in res:
print(f'V={value[0]}) {value[1]} |-> ',end='')
if __name__ == '__main__':
path = combine(4,4,16)
prettify_result(path)
说明
-
我首先想到的是用 Rat in a Maze 算法的 Backtracking 技术解决的Depth-first_search 问题,该算法以 时间复杂度运行:O(2^(n^2 )) 但经过审查后,我对此表示怀疑,这似乎更像是一种 Dijkstra's algorithm,但我可能是错的。我认为 回溯 并不简单,因为它不是递归的(并且从不回溯...),但是因为它检查节点的权重,所以它似乎是具有给定 Max- 的 Dijkstra's-重量。
-
重要提示,迷宫是从下到上颠倒解决的!所以它从值 4 开始向后运行!因此实际上正在检查:
- 优先向上。
- Direction LEFT 一直在检查每一步(我在脚本中留下了很大的注释),如果不能去(因为成本太高)然后它上升(上升成本)少一个,因为它是 4,3,2,1)
-
“函数移动,什么是最少的 + (count - (max_val - 1)) * (max_val - 1)” 这个我也很难理解,基本上只是一个数学技巧,我补充说它在一个名为
check_row
的变量中以使其更加明确,但基本上它会检查是否可以向左移动。 -
在算法结束时,它向后反转列表,看起来像是从上到下。
考虑
-
函数
move()
始终返回 2 个值,其中第一个 ifFalse
和 store 位于变量result
中,但甚至未使用。这很奇怪(似乎没有编程实践)并且无论如何都没有使用,所以我只是将其删除并替换为break
语句。那是因为在 while 循环中中断而不是返回更有意义。然后,函数会注意return path
最后。 -
我删除了许多针对 0 的
while max_val > 0
或类似的bool
检查,因为它是完全多余的,而不是 Pythonic,如指南 realpython.com/python-conditional-statements/
在线文档
回溯
深度优先搜索
Dijkstra 算法