题目描述
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入
输入的第一行为一个整数n,表示棋盘的大小。 n小于等于8
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出
输出一个整数,表示总共有多少种放法
思路:
先放白皇后再放黑皇后
其实本质是利用回溯,回溯的基本模板:
void backtracking(参数) {
if (终⽌条件) {
存放结果;
return;
}
for (选择:本层集合中元素(树中节点孩⼦的数量就是集合的⼤⼩)) {
处理节点;
backtracking(路径,选择列表); // 递归
回溯,撤销处理结果
}
}
n = int(input())
a = []
for i in range(n):
a.append(list(map(int,input().split()))) #创建二维数组
count = 0 #记次数
def brak(row,n,s,a):
global count #要设为全局变量,不然就会为0
if row == n: #判断是否放到最后一行
if s ==2 : #白皇后放完了,就放黑皇后
brak(0,n,3,a)
if s ==3: #黑皇后也放完了
count = count+1
return
for i in range(n):
if a[row][i] != 1: #不是1证明这里不能放皇后,顺便判断同行有没有皇后
continue
if check(row,i,s,a): #row,i横列坐标,s白皇后还是黑皇后,a数组
a[row][i]=s
brak(row+1,n,s,a)
a[row][i]=1
def check(row,i,s,a):
for j in range(row-1,-1,-1):
if a[j][i]==s: #判断同列是否有皇后
return False
r,c = row-1,i-1
while r>=0 and c>=0: #检查左上角
if a[r][c]==s:
return False
r,c = r-1,c-1 #应该要自己递减,而不是靠row,i来减一
r,c = row-1,i+1
while r>=0 and c<n: #检查右上角,c的条件没有判断好,不能c>=0
if a[r][c]==s:
return False
r,c = r-1,c+1
return True
brak(0,n,2,a)
print(count)