# 第一种:套用子集树模板 # 定义棋盘大小(八皇后问题,所以是8),同时也表示皇后的数量 n = 8 # 用于记录当前尝试放置皇后过程中每一行皇后所在的列位置,初始为空列表 x = [] # 用于存储所有找到的满足八皇后问题条件的皇后放置方案,每个方案也是一个列表,记录每一行皇后所在列位置 X = [] # 判断在第k行放置的皇后是否与前面已经放置的皇后(第0行到第k - 1行)产生冲突 def conflict(k): global x # 遍历前面已经放置皇后的行(从第0行到第k - 1行) for i in range(k): # 判断当前放置在第k行的皇后与第i行的皇后是否在同一列 if x[i] == x[k]: return True # 判断当前放置在第k行的皇后与第i行的皇后是否在同一对角线上 # 利用同一对角线上的两个位置,其行索引差的绝对值和列索引差的绝对值相等这一特性来判断 elif abs(i - k) == abs(x[i] - x[k]): return True # 如果遍历完前面所有行都没有发现冲突,则返回False return False # 通过递归回溯的方式尝试在棋盘上放置皇后,找出所有满足八皇后问题条件的放置方案 def queens(k): global n, x, X # 基本情况判断:如果k >= n,意味着已经成功放置了n个皇后(填满了棋盘的每一行) if k >= n: # 打印当前找到的皇后放置方案 print(x) # 将当前方案x的副本(浅拷贝)添加到列表X中,用于存储所有找到的方案 X.append(x[:]) else: # 尝试在第k行的每一列(从第0列到第n - 1列)放置皇后 for i in range(n): # 将列索引i添加到列表x中,表示在第k行的第i列放置了皇后 x.append(i) # 检查这个放置是否有冲突,如果没有冲突 if not conflict(k): # 继续递归调用queens函数,去尝试在下一行(第k + 1行)放置皇后 queens(k + 1) # 如果有冲突或者后续放置不符合要求,需要回溯,将刚刚在第k行放置的皇后移除 x.pop() # 用于展示给定的一种皇后放置方案对应的棋盘布局情况 def show(z): global n # 遍历棋盘的每一行(从第0行到第n - 1行) for i in range(n): # 根据传入的皇后放置方案列表z中记录的每一行皇后所在列位置,打印出相应的棋盘表示 # 先打印'. '重复z[i]次(表示皇后前面的空白格子),然后打印'X'表示皇后所在位置 # 接着再打印'. '重复n - z[i] - 1次(表示皇后后面的空白格子) print('. ' * z[i] + 'X' + '. ' * (n - z[i] - 1)) # 从第0行开始放置皇后,启动递归回溯过程来寻找所有满足条件的八皇后放置方案 queens(0) # 打印出存储所有方案的列表X中的最后一个元素,也就是最后一种找到的八皇后放置方案,并换行 print(X[-1], '\n') # 调用show函数展示最后一种找到的八皇后放置方案对应的棋盘布局情况 show(X[-1])
# 第二种:通过回溯算法实现条件过滤 # 定义棋盘的最大坐标,即8x8的棋盘 max_coordinate = 8 # 初始化一个列表来存储每一列放置皇后的行号,None表示尚未放置 queen_list = [None] * 8 # 定义一个函数来显示当前棋盘的状态 def show(): column = 0 while column < max_coordinate: # 打印每一列的皇后位置,格式为 (列, 行) print("(%d,%d) " % (column, queen_list[column]), end="") column += 1 print("") # 定义一个函数来检查当前放置的皇后是否与之前放置的皇后冲突 def check(column): for column_2 in range(column): # 检查是否在同一行 if queen_list[column_2] == queen_list[column]: return False # 检查是否在同一对角线 elif abs(queen_list[column_2] - queen_list[column]) == column - column_2: return False return True # 定义一个递归函数来尝试在每一列放置皇后 def put_queen(column): for row in range(max_coordinate): queen_list[column] = row if check(column): if column == max_coordinate - 1: # 如果已经放置了所有皇后,打印当前棋盘状态 show() else: # 递归地在下一列放置皇后 put_queen(column + 1) # 定义主函数,从第一列开始尝试放置皇后 def main(): put_queen(0) print("-" * 10) # 如果这是主模块,则执行主函数 if __name__ == '__main__': main()
# 第三种:递归回溯 def queen(queen_list, current_column=0): # 棋盘的大小 size = len(queen_list) # 如果已经放置了所有皇后,打印当前的解 if current_column == size: for i in range(size): print("(%d,%d)" % (i, queen_list[i]), end="") print(" ") return # 尝试在当前列的每一行放置皇后 for row in range(size): # 假设当前行可以放置皇后 flag = True # 检查当前行是否与之前放置的皇后冲突 for column in range(current_column): if (queen_list[column] == row) or (abs(row - queen_list[column]) == current_column - column): flag = False break # 如果当前行没有冲突,则放置皇后并递归到下一列 if flag: queen_list[current_column] = row queen(queen_list, current_column + 1) # 初始化棋盘,None表示尚未放置皇后 queen([None] * 8)
# 第四种:判断皇后的落点是否合规 import random # 检查在给定的皇后放置状态下,下一个皇后放置在指定列(nextX)是否会产生冲突 def conflict(state, nextX): # 冲突检测函数,用于判断新放置的皇后是否与已放置的皇后冲突。 # 参数: # - state: 一个元组,表示已经放置的皇后的列位置信息,例如(1, 3) # 表示第1列皇后在第2行(索引从0开始),第2列皇后在第4行。 # - nextX: 一个整数,表示下一个皇后要放置的列位置(对应的行位置还未确定,这里通过此函数判断可行性)。 # 返回值: # - 如果新放置的皇后与已放置的皇后存在冲突(在同一行、同一对角线),则返回True;否则返回False。 nextY = len(state) # 获取已放置皇后的数量,也就是下一个皇后要放置的行坐标(棋盘是按行列表示,这里用行数来对应纵坐标) for i in range(nextY): # 检查是否在同一行(state[i] - nextX 的差值为0表示在同一行)或者在同一对角线(差值的绝对值等于行与列的差值绝对值) if abs(state[i] - nextX) in (0, nextY - i): return True return False # 通过递归生成器的方式来生成所有满足条件的皇后放置方案 def queens(num, state=()): # 递归生成器函数,用于生成指定数量皇后在棋盘上的所有满足条件的放置方案。 # 参数: # - num: 一个整数,表示皇后的总数量,也就是棋盘的边长(例如num为8表示8x8的棋盘放置8个皇后)。 # - state: 一个元组,用于记录已经放置的皇后的列位置信息,默认初始为空元组,表示还未开始放置皇后。 # 返回值: # - 生成器对象,每次迭代返回一个元组,表示一种皇后放置方案,元组中的每个元素代表对应列皇后所在的行位置。 for pos in range(num): if not conflict(state, pos): # 如果已经放置了num - 1个皇后(即只差最后一个皇后就全部放置完成),则返回当前皇后位置的元组作为一种方案 if len(state) == num - 1: yield (pos,) else: # 如果还没到只差最后一个皇后的情况,继续递归调用queens函数,传入更新后的状态(已放置皇后位置信息) for result in queens(num, state + (pos,)): yield (pos,) + result # 用于以可视化的形式打印出皇后放置方案在棋盘上的样子 def prettyprint(solution): # 函数用于将皇后放置方案以直观的棋盘形式打印出来,用 # '.' # 表示空白格子,'x' # 表示皇后所在位置。 # 参数: # - solution: 一个元组,表示一种皇后放置方案,元组中的元素对应各列皇后所在的行位置。 def line(pos, length=len(solution)): # 内部函数,用于生成表示一行棋盘布局的字符串,根据皇后所在的列位置(pos),在相应位置放置 # 'x',其余位置用 # '.' # 填充。 # 参数: # - pos: 一个整数,表示皇后在当前行所在的列位置。 # - length: 一个整数,默认取solution的长度,表示棋盘的总列数,也就是皇后的总数量。 # 返回值: # - 一个字符串,表示一行棋盘的布局情况。 return '.' * (pos) + 'x' + '.' * (length - pos - 1) for pos in solution: print(line(pos)) if __name__ == "__main__": solutions = list(queens(8)) # 获取所有的皇后放置方案列表 for solution in solutions: prettyprint(solution) # 逐个打印每个方案对应的棋盘布局 print("-" * 20) # 打印分隔线,方便区分不同的方案展示
返回结果: 第一种:
第二种:
第三种:
第四种: