八皇后问题

描述

  将8个皇后放在8*8的棋盘上,要求这8个皇后两两不能在同一水平、垂直或对角线上,求所有放置方法。

求解

  这是一道经典的递归问题(当然也可以暴力枚举,但不够雅观简洁),8*8的棋盘递归后转变为7*7的棋盘来解决,7*7的棋盘递归后转变为6*6的棋盘来解决,……,但这里的问题是前面的放置会影响后面的放置情况,所以还需要一个记录放置状态的全局变量;后面的放置不成功还会回溯到前面的情况重新放置,所以还要分不同的情况来回溯。

  作为一道递归题,当然只需要解决两部分即可:终止条件和递归核心。

终止条件

  终止条件只有一个,即已经填完所有的8皇后,显然返回就行了。

递归核心

  枚举当前行内所有点,如果能成功放置,则放置,并调用下一层递归;如果不能,则自继续枚举该行的下一个点。

  判断放置成功的条件为:

  在水平、垂直线上都比较容易判断,关键是在对角线上的判断为:设两个点为(x1, y1), (x2, y2),则两个点在对角线上应满足(斜率是±1)两条直线方程:x1 + y1 = x2 + y2 (主对角线),x1 - y1 = x2 - y2(副对角线)。

数据结构

  由于每一行只能放置一个皇后,所以只需要用一个一位数组记录即可,第i行放置了第j列的皇后,记为a[i] = j,这样空间复杂度从O(n²)变为O(n)

代码

  用Python递归版的代码可以非常简洁:

num_queen = 8
count = 0
queen_col = [0] * num_queen

def recursion(cur_row = 0):
    global num_queen
    global queen_col
    global count
    # stop condition
    if cur_row == num_queen:
        count += 1
        print(queen_col)
        return
    # main recursion process
    for i in range(num_queen):
        queen_col[cur_row] = i 
        flag = True
        # check if the current point is available
        # only check the row before the current row
        for j in range(cur_row):
            x1 =  j
            y1 = queen_col[j]
            x2 = cur_row
            y2 = queen_col[cur_row]
            if y1 == y2 or x1+y1 == x2+y2 or y1-x1 == y2-x2:
                flag = False
                break
        if flag:
            recursion(cur_row+1)

recursion()
print(count)

  输出共92种方法

原文地址:https://www.cnblogs.com/sbj123456789/p/10519278.html