Python算法问题|如何在连通图中找到期望权重的路径?

问题描述

问题

假设你有一个像这样的 m * n 矩阵:

Grid = 4 * 4

1 1 1 1    
2 2 2 2    
3 3 3 3    
4 4 4 4

你想从左上角连接到右下角,你只能向右或向下。此外,您还想找到获得所需总和所需的操作。

例如:

enter image description here

在教科书中找到的脚本,不清楚

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))):

问题

  1. 这个算法的名称是什么?
  2. 这个脚本是如何工作的?
  3. 运行时间(时间复杂度)是多少?

谢谢!

解决方法

所以脚本写得不好,也没有遵循最佳实践,不得不说我重新调整了它,希望更清晰

源代码

注意:我已经添加到我的 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)

说明

  1. 我首先想到的是用 Rat in a Maze 算法的 Backtracking 技术解决的Depth-first_search 问题,该算法以 时间复杂度运行:O(2^(n^2 )) 但经过审查后,我对此表示怀疑,这似乎更像是一种 Dijkstra's algorithm,但我可能是错的。我认为 回溯 并不简单,因为它不是递归的(并且从不回溯...),但是因为它检查节点的权重,所以它似乎是具有给定 Max- 的 Dijkstra's-重量。

  2. 重要提示,迷宫是从下到上颠倒解决的!所以它从值 4 开始向后运行!因此实际上正在检查:

    • 优先向上
    • Direction LEFT 一直在检查每一步(我在脚本中留下了很大的注释),如果不能去(因为成本太高)然后它上升(上升成本)少一个,因为它是 4,3,2,1)
  3. “函数移动,什么是最少的 + (count - (max_val - 1)) * (max_val - 1)” 这个我也很难理解,基本上只是一个数学技巧,我补充说它在一个名为 check_row 的变量中以使其更加明确,但基本上它会检查是否可以向左移动。

  4. 在算法结束时,它向后反转列表,看起来像是从上到下。


考虑

  1. 函数 move() 始终返回 2 个值,其中第一个 if False 和 store 位于变量 result 中,但甚至未使用。这很奇怪(似乎没有编程实践)并且无论如何都没有使用,所以我只是将其删除并替换为 break 语句。那是因为在 while 循环中中断而不是返回更有意义。然后,函数会注意return path最后。

  2. 我删除了许多针对 0 的 while max_val > 0 或类似的 bool 检查,因为它是完全多余的,而不是 Pythonic,如指南 realpython.com/python-conditional-statements/


在线文档

回溯

深度优先搜索

Dijkstra 算法