蓝桥杯Python-2n皇后问题(和别人的想法有点不一样)

发布于:2022-12-06 ⋅ 阅读:(504) ⋅ 点赞:(0)

首先附上问题链接:蓝桥杯基础练习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)是空的!!!这样第一行如果有不能放置皇后的位置就不能察觉到了

困扰了好久,觉得自己思路挺正确的,但是提交就是出错,淦。后面打印调试了好久才发现。

本文含有隐藏内容,请 开通VIP 后查看