N皇后问题

问题描述
要求找出一个nxn棋盘上放置n个皇后并使其不能相互攻击的所有方案。即任意两个皇后不在同一行或同一列,且不在同一斜角线上。
解决思想
利用回溯的方法来解决,对于回溯问题,一个好的限界函数会起到很好的效果,否则,可能效果很差。
代码实现

import matplotlib.pyplot as plt 
import copy 

# 限界函数,来判断是否可放置一个皇后
def place(X,k):
    # 如果一个皇后能放在第k行和X(k)列,则返回true;否则返回false。
    # X是一个全程数组(在python中换成列表),进入此过程时已置了k个值。
    # abs(r)过程返回r的绝对值
    i=0
    while(i<k):
        if X[i]==X[k] or abs(X[i]-X[k])==abs(i-k):
            return False
        i+=1
    return True

# n-皇后问题的所有解
def nqueens(n):
    # 此过程使用回溯法求出一个nxn棋盘上放置n个皇后,使其不能相互攻击的所有可能位置
    # global X
    allX=[]    #该变量用于存放所有的可行解
    X=[-1]  #给X赋初值,即X[0]=-1
    k=0   #k为当前行,给它赋0只是下标对应的0,实际指第一行
    while(k>-1):
        X[k]+=1  #移到下一列
        while(X[k]<=n-1 and not place(X,k)): #判断此处能否放置该皇后
            X[k]+=1
        if X[k]<=n-1:   #找到一个位置
            if k==n-1:   #判断是否是完整的解
                allX.append(copy.deepcopy(X)) #需要进行深拷贝,否者值会被删除(因为是引用)
                # print(X)
                # print(allX)
            else:
                k+=1
                X.append(-1)  #相当于给X[k]赋值-1,即转到下一行
        else:
            X.pop(-1)
            k-=1
    return allX

# 绘图函数,将各个解对应的情况绘制出来
def plot(allX2):
    length=len(allX2) #解的数量
    name=1      #图片名字,以序号命名
    for i,X in enumerate(allX2):
        tick=list(range(len(X)))    #坐标轴上的刻度值
        x_data=[]       #点的横坐标
        y_data=[]       #点的纵坐标
        for j,value in enumerate(X):
            x_data.append(value+0.5)
            y_data.append(j+0.5)
        if(i%16==0):
            plt.figure(i//16+1) #生成一个新图
        plt.subplot(4,4,i%16+1) #每张图最多画16个子图
        plt.scatter(x_data,y_data)
        plt.title(str(i+1))
        plt.xticks(tick)
        plt.yticks(tick)
        plt.grid(True)
        if(i%16==15 or i==length-1):
            # print(i,length-1)
            plt.savefig(str(name)+'.jpg')  #保存图片
            name+=1
            plt.show()
            
    

if __name__=='__main__':
    plot(nqueens(8))  #实现8皇后问题

实现效果
由于不知道咋在一行显示多张图片,只能这样看了(卑微)
在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值