乐趣区

算法由浅入深回溯法

我理解的回溯法

  1. 回溯法本质上就是穷举法,对穷举法的优化,优化的关键在于判断哪些情况是不需要考虑的,然后不去遍历这些不必要的情况(剪枝)。
  2. 理解穷举法,要理解回溯法就要先真正明白穷举法。用下面例题来理解一下穷举法

输出给的数字的全排列

输入:1 2 3

输出:

[[1, 2, 3], 
[1, 3, 2], 
[2, 1, 3], 
[2, 3, 1], 
[3, 1, 2], 
[3, 2, 1]
]

核心步骤的伪代码:

Permutation(array A, array B){
    If Array B is OK
        Return array A
    Else 
        For I in B:
        Permutation(A add I, B remove I)
}

Python 实现:

# Full Permutation 全排列
def permute(numbers: list):
    sorted(numbers)
    visited = [0 for i in numbers]
    output = []
    middle = []
    helper(numbers, visited, middle, output)
    return output


def helper(numbers: list, visited: list, middle: list, output: list):
    if len(middle) is len(numbers):
        output.append(middle.copy())
        return
    for i in range(0, len(numbers)):
        if visited[i] is 0:
            visited[i] = 1
            middle.append(numbers[i])
            helper(numbers, visited, middle, output)
            visited[i] = 0
            middle.pop()


if __name__ == '__main__':
    nums = [1, 2, 3]
    print(permute(nums))
  1. N 皇后问题,这个在回溯法中比较经典,我们理解了穷举法的全排列,就可以试着理解 N 皇后问题,其实全排列实现也是用到了回溯的思想。

我们以 8 皇后为例,8* 8 的棋盘上,放 8 个皇后的棋子,使他们不能在同行同列和对角线上。

输入:8

输出:92

Python 实现:

# N queen n 皇后问题
def n_queens(n: int):
  output = [0]
  middle = [-1 for i in range(0, n)]
  compute_n_queen(n, 0, middle, output)
  return output[0]
 
 
def compute_n_queen(n: int, row: int, middle: list, output: list):
  if n is row:
    output[0] += 1
    return
  # 一行一行来
  for column in range(0, n):
    flag = 1
    middle[row] = column
    # 这里回溯之前放置的棋子,是否和这次放置的冲突,也就是回溯法的剪枝
    for j in range(0, row):
      # 因为我们是一行一行判断的,所以不用判断是否在同一行,只判断是否在同一列
      # 是否在同一对角线判断即行列相减相加是否相同
      if middle[row] is middle[j] or row - middle[row] is j - middle[j] or row + middle[row] is j + middle[j]:
        flag = 0
        break
    if flag:
      compute_n_queen(n, row + 1, middle, output)
 
 
if __name__ == '__main__':
  print(n_queens(8))
 
退出移动版