首先附上问题链接:蓝桥杯基础练习VIP-2n皇后问题 - C语言网 (dotcpp.com)
问题描述:
给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。
输入:
输入的第一行为一个整数n,表示棋盘的大小。 n小于等于8
接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。
输出:
输出一个整数,表示总共有多少种放法。
要做好2n皇后需要首先学会n皇后问题,这里推荐一个视频,虽然是用C写的但思路很清晰,唯一不足的地方是在dfs(row+1)后面的a[row]=0,这里有点画蛇添足了,我的理解是dfs完row+1层返回后仍然会继续进行for循环,没有必要将a[row]置为0,反而会让人难以理解(想了好一会才想通)。
这里附上n皇后的Python代码(不要直接看我的,自己动手去写一遍才是自己的!!!):
n = int(input())
## cnt记录可行解的数量
cnt = 0
## a记录可行的放置方法 分别对应第0 1 2 ... n行皇后放置的位置
a = []
## 这里添加n个0是因为n行要放n个皇后,这里置为0不影响,后面会覆盖的,只起到一个占位置的作用
for i in range(n):
a.append(0)
## check函数 检查第x行的皇后能否放置在y位置上 注意这里的位置从0开始
def check(x,y):
for i in range(x):
## 这里可能有一点难以理解 你可以类比于把皇后们放在坐标上 然后直线(一共三条)就可以用y=kx+b表示 非常好理解
if a[i] == y or a[i]+i == x+y or a[i]-i == y-x:
return False
return True
## dfs函数 进行深度优先搜索
def dfs(k):
## 如果已经到达过了底层就返回(这里层数也从0开始 所以第n-1层才是最底层)并且打印放置方法
if k == n:
global cnt
cnt += 1
print(a)
return
## 没到底就继续深度搜索
for i in range(n):
if check(k,i):
a[k] = i
dfs(k+1)
dfs(0)
print(cnt)
完成n皇后问题后,这里就出现了不一样的地方了,我的想法是既然n皇后已经可以列举除可以放置的方案,那么我直接将n皇后的方案进行组合即可,只需要判断任一的两个方案之间是否有冲突例如 如果n为4,并且所有位置都能放皇后,那么n皇后的解为:
[1, 3, 0, 2]
[2, 0, 3, 1]
2
由于[1, 3, 0, 2]和[2, 0, 3, 1]位置并不冲突所以可以组合成2n皇后的一个解,同时黑白皇后各自可以选择不同的方案,所以2n皇后的解为 1*2 = 2个
这里附上我的2n皇后Python代码:
n = int(input())
hmap = []
## hmap记录是否可以放皇后
a = []
for i in range(n):
## 这里同样只起占位作用
hmap.append([])
a.append(0)
hmap[i] = list(map(int,input().split()))
## one_list记录hmap条件下n皇后的可行解
one_list = []
#cnt记录hmap条件下n皇后解的数目 ans为2n皇后解的个数
cnt = 0
ans = 0
def check(x,y):
## 这里有坑!!!!
## range(0)是空的!!! 所以需要看x是不是0行 否则直接就返回True了
## 还是c方便 ~ ̄▽ ̄~
if x == 0 and hmap[x][y] == 0:
return False
for i in range(x):
if hmap[x][y] == 0:
return False
if a[i] == y or a[i]+i == x+y or a[i]-i == y-x:
return False
return True
def dfs(k):
if k == n:
global cnt
cnt += 1
one_list.append(a[:])
return
for i in range(n):
if check(k,i):
a[k] = i
dfs(k+1)
## 判断n皇后解是否有位置相同
def notsame(x,y):
for i in range(n):
if one_list[x][i] == one_list[y][i]:
return False
return True
dfs(0)
for i in range(len(one_list)):
for j in range(i+1,len(one_list)):
if notsame(i,j):
ans += 1
## 黑白选择方案有组合数 A(2-2)=2
print(2*ans)
唯一需要注意的地方就是range(0)是空的!!!这样第一行如果有不能放置皇后的位置就不能察觉到了
困扰了好久,觉得自己思路挺正确的,但是提交就是出错,淦。后面打印调试了好久才发现。