Python:暴力破解解决八皇后问题

问题:有一个8乘8的棋盘,现在要将八个皇后放到棋盘上,满足:对于每一个皇后,在自己所在的行、列、两个对角线都没有其他皇后。

在这里插入图片描述


想法:首先规定同列只能出现一个皇后。每一个棋盘,对应于一个长度为8的串,每一个数的范围是[1, 8],第k个数字所代表的含义是第k列中皇后所在的行数,如[3,2,5,4,3,2,1,3]代表棋盘上从第一列到第八列,皇后所摆放的行数分别为第3,2,5,4,3,2,1,3行。


程序1:generate_init_seq.py。如果8个皇后在8*8的棋盘上可以随意摆放,当然是不能在同一个格子里放超过一个皇后的情况下,本来所有需要测试是否满足要求的序列共有64*63*…*57=1.78e+14个,这太多了。所以此程序的工作是筛选出那些【每行与每列都只有一个皇后存在】的序列,这样的序列有8*7*6*5*4*3*2=40320个,可以大大缩减了后续程序的运行时间,而且这样在后面处理每个序列时只需要考虑两条对角线上有没有其他皇后即可。如下:

import json, time

start = time.time()

seq = [[i, j, k, l, m, n, o, p]
       for i in range(1, 9)
       for j in range(1, 9)
       for k in range(1, 9)
       for l in range(1, 9)
       for m in range(1, 9)
       for n in range(1, 9)
       for o in range(1, 9)
       for p in range(1, 9) 
       if all([i!=j, i!=k, i!=l, i!=m, i!=n, i!=o, i!=p,
               j!=k, j!=l, j!=m, j!=n, j!=o, j!=p,
               k!=l, k!=m, k!=n, k!=o, k!=p,
               l!=m, l!=n, l!=o, l!=p,
               m!=n, m!=o, m!=p,
               n!=o, n!=p,
               o!=p])] # 筛选出那些【每行与每列都只有一个皇后存在】的序列
print('有' + str(len(seq)) + '个可能的序列')
with open('seq.json', 'w') as file_object:
    json.dump(seq, file_object)

end = time.time()
print('Successful!')
print('已将生成的序列存储到文件seq.json中,用时' + str('%.2f' % (end-start)) + 's')

输出如下。注意会生成一个文件seq.json,我上传到了csdn上,你可以看看这里,你也可以运行程序1,在自己电脑上得到一个文件,和我这个是一样的:

40320个可能的序列
Successful!
已将生成的序列存储到文件seq.json中,用时23.78s

程序2:main.py。如下:

import json
import numpy as np

with open('seq.json', 'r') as file_object:
    seq = json.load(file_object) # 载入保存好的序列

solutions = 0 # 记录有几个解

for s in seq:
    a = np.array([0] * 81) # 在开始时创建一个有81个0的一维数组
    a = a.reshape(9,9) # 改变为9*9二维数组,为了后面方便使用,只用后八行和后八列的8*8部分,作为一个空白棋盘
    
    flag = 1 # 假设当前序列对应的棋盘满足条件
    
    for i in range(1, 9):
        a[s[i-1]][i] = 1 # 根据序列,从第一列到最后一列的顺序,在对应位置放一个皇后,生成当前序列对应的棋盘
    
    for i in range(1, 9): # 检查当前序列的八个皇后在各自的两条对角线上是否有其他皇后
        t1 = t2 = s[i-1]
        for j in range(i-1, 0, -1): # 看左半段
            if t1 != 1:
                t1 -= 1
                if a[t1][j] == 1:
                    flag = 0 # 正对角线左半段上有其他皇后,表示当前序列不满足条件,不用再检查次对角线左半段、正对角线右半段、次对角线右半段
                    break
            
            if t2 != 8:
                t2+= 1
                if a[t2][j] == 1:
                    flag = 0 # 次对角线左半段上有其他皇后,表示当前序列不满足条件,不用再检查正对角线右半段、次对角线右半段
                    break
        
        if flag == 0:
            break # 当前序列不满足条件,不用再检查正对角线右半段、次对角线右半段
        
        t1 = t2 = s[i-1] # 如果能到这步,说明正对角线左半段、次对角线左半段符合条件,继续检查右半段
        for j in range(i+1, 9): # 看右半段
            if t1 != 1:
                t1 -= 1
                if a[t1][j] == 1:
                    flag = 0 # 正对角线右半段上有其他皇后,表示当前序列不满足条件,不用再检查次对角线右半段
                    break
            
            if t2 != 8:
                t2+= 1
                if a[t2][j] == 1:
                    flag = 0 # 次对角线右半段上有其他皇后,表示当前序列不满足条件
                    break
        
    if flag == 1: # 经过层层筛选,如果序列符合条件则执行下面内容
        solutions += 1 # 计数+1
        print('第' + str(solutions) + '个解,此序列:'+ str(s) + ' 符合条件,对应棋盘如下:')

        for i in a[1:]: # 输出对应棋盘
            for j in i[1:]:
                print(j, ' ',end="") # 有了end="",print就不会换行
            print() # 输出完一行后再换行,这里不能是print('\n'),否则会换两行

        print('---------------') # 分割线
print('共' + str(solutions) + '个解') # 最后再明确一下有几个解

输出:

1个解,此序列:[1, 5, 8, 6, 3, 7, 2, 4] 符合条件,对应棋盘如下:
1  0  0  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  0  0  1  0  0  0  
0  0  0  0  0  0  0  1  
0  1  0  0  0  0  0  0  
0  0  0  1  0  0  0  0  
0  0  0  0  0  1  0  0  
0  0  1  0  0  0  0  0  
---------------2个解,此序列:[1, 6, 8, 3, 7, 4, 2, 5] 符合条件,对应棋盘如下:
1  0  0  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  0  1  0  0  0  0  
0  0  0  0  0  1  0  0  
0  0  0  0  0  0  0  1  
0  1  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
0  0  1  0  0  0  0  0  
---------------3个解,此序列:[1, 7, 4, 6, 8, 2, 5, 3] 符合条件,对应棋盘如下:
1  0  0  0  0  0  0  0  
0  0  0  0  0  1  0  0  
0  0  0  0  0  0  0  1  
0  0  1  0  0  0  0  0  
0  0  0  0  0  0  1  0  
0  0  0  1  0  0  0  0  
0  1  0  0  0  0  0  0  
0  0  0  0  1  0  0  0  
......92个解,此序列:[8, 4, 1, 3, 6, 2, 7, 5] 符合条件,对应棋盘如下:
0  0  1  0  0  0  0  0  
0  0  0  0  0  1  0  0  
0  0  0  1  0  0  0  0  
0  1  0  0  0  0  0  0  
0  0  0  0  0  0  0  1  
0  0  0  0  1  0  0  0  
0  0  0  0  0  0  1  0  
1  0  0  0  0  0  0  0  
---------------92个解

在不考虑对称性的情况下,解共有92个,我在上面的输出中只放了第1、2、3、92个解。因为太多,都放的话会占太多篇幅。想获取全部的解,你可以下载这个文件,也可以在自己电脑上运行程序2,可以得到一个文件,和我这个是一样的。


评价:自己认为程序中写的注释很好,哈哈!


END

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值