8皇后问题是回溯算法的经典案例,回溯又称深搜,简单来说就是递归的枚举。
回溯算法优于穷举在于一旦遇到达不到目标或不优,立即向上返回重新选择,寻找别的路径。
有点像暴力破解,不过一旦不达目标则不继续当前方案,因此是比暴力破解省下减少很多运算量
问题描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入格式
输入的第一行为一个整数n,表示棋盘的大小。
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出格式
输出一个整数,表示总共有多少种放法。
样例输入
4
1 1 1 1
1 1 1 1
1 1 1 1``
1 1 1 1
样例输出
2
具体实现参考别人的方案加了一点内容,过程如下:
while True:
try: # 先放白皇后,再放黑皇后
n = int(input()) # n是一开始的黑白皇后的个数
s = [] # 存放原始的0,1位置
result = []
temp_W = [None for x in range(n)] # 临时存放白皇后
temp_B = [None for x in range(n)] # 临时存放黑皇后
for i in range(n):
s.append(input().split()) # 输入0,1位置
def valid_W(temp_W, row): # 判断当前位置放白皇后是否合法
if s[row][temp_W[row]] == "1":
for i in range(row):
# 下面这个判断条件是:判断对角线,判断是否是白皇后自己的列
if abs(temp_W[i] - temp_W[row]) == abs(i - row) or temp_W[i] == temp_W[row]:
return False
return True
def valid_B(temp_B,row,temp_W): # 判断当前位置放黑皇后是否合法
if s[row][temp_B[row]] == '1' and temp_B[row] != temp_W[row]: # 判断这个位置能否放皇后
for i in range(row):
# 判断是否对角线,是否是自己的列,判断这个位置有没有先放白皇后
if abs(temp_B[i] - temp_B[row]) == abs(i-row) or temp_B[i] == temp_B[row]:
return False
return True
def dfs_W(temp_W,row): # temp记录当前所有合法的皇后的位置,row是继续往下一行里面放皇后
if row == n: # 当前进行到n,表示找到了白皇后的一种排列方式,跳出递归
dfs_B(temp_B,0) # 白皇后排好之后跳到排列黑皇后
else:
for col in range(n): # col是列,就是要遍历这一行的所有列,判断在某个位置上是否合法
temp_W[row] = col
if valid_W(temp_W,row):
dfs_W(temp_W,row+1)
def dfs_B(temp_B,row): # temp记录当前所以合法皇后的位置,row是继续往下一行里面放皇后
if row == n: # 当前进行到n,表示找到了n皇后的一种排列方式,跳出递归
result.append(temp_B[:]) # 将找到的黑皇后排列方式存储到result里面
return
else:
for col in range(n): # col是列,遍历这一行所有列,判断在某位置是否合法
temp_B[row] = col
if valid_B(temp_B,row,temp_W):
dfs_B(temp_B,row+1)
dfs_W(temp_W,0)
print(len(result))
except:
break # 通过异常输入跳出循环(如不输入直接运行)