题目描述:
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种方法?n小于等于8。
输入:
输入的第一行为一个整数n,表示棋盘的大小。 n小于等于8
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出:
输出一个整数,表示总共有多少种放法。
样例输入:
4 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
样例输出:
2
注:本人也是刚学,还是个废人,啥都不明白,如有错误,还请指正。在CSDN发的第一篇文章,希望以后能在此与大家一同进步,同时也给我自己记记笔记。
注:代码思路借鉴于Leecode 八皇后官方解答的基于集合的回溯,自己只想到了记录数据减少递归次数提高效率,没想到代码咋写,看了官方思路后恍然大悟
#记录数据 直接排除不能放的位置 利用横纵坐标的关系 正对角线 x+y为定值 反对角线:x-y为定值
#因为每行放完一个皇后以后就会放下一个 所以不用考虑同一行的
#利用列表提早记下哪条对角线 哪一列上有皇后 提高递归的效率
count = 0
def bfs(Map,row,incline,tst,lie,ast,ost,gst):
if row == len(Map):
global count
count +=1
return
for i in range(len(Map)):
if (row-i) in incline or i in lie or Map[row][i] == 0 or (row + i) in tst:
continue
else:
incline.append(row - i)#反对角线
tst.append(row + i)#正对角线
lie.append(i) #根据这一格的横纵坐标 来排除剩下几行不能放的位置(对角线 和 纵列)
Map[row][i] = 2#放置黑/白皇后 自己认为是那个就是那个
for u in range(len(Map)):
if (row - u) in ast or u in gst or Map[row][u] == 2 or Map[row][u] == 0 or (row+u) in ost: #排除位置
continue
else: #没被排除就放
ast.append(row - u)
ost.append(row + u)
gst.append(u) #同上
Map[row][u] = 3#放置白/黑皇后
bfs(Map,row+1,incline,tst,lie,ast,ost,gst)
Map[row][u] = 1 #进行回溯 一、拿到结果后还原棋盘 二、不满足条件时还原棋盘 从而进行改变棋子位置寻找正解
#比如 不满足的其中一个[2,3,1,1],[1,1,2,3]这两行放完以后,下一行就没法放了
#于是递归回溯 执行这一行代码 恢复棋盘为[2,3,1,1],[1,1,2,1]
ast.remove(row - u)
ost.remove(row + u)
gst.remove(u)
Map[row][i] = 1#这一行回溯为[2,3,1,1],[1,1,1,1] 之后棋盘第二行的递归函数执行完毕后回溯 修改棋盘第一行的棋子位置 寻找正解
incline.remove(row - i)
tst.remove(row+i)
lie.remove(i)
if __name__ == '__main__':
Map,ost,tst,incline, lie, ast, gst = [],[],[],[],[],[],[]
m = int(input())
for _ in range(m):
Map.append(list(map(int,input().split())))
bfs(Map, 0, incline,tst,lie, ast,ost,gst)
print(count)