n皇后问题的最优解及优化

n皇后问题的最优解

时间复杂度    O(n^{n})

package algorithm;

public class NQueen {
    public static int num(int n){
        if(n < 1){
            return 0;
        }
        int[] record = new int[n];//n皇后的n*n的棋盘,record[i]表示第i行的皇后放在了第几列
        return process(0,record,n);
    }

    /**
     *返回n皇后的摆法
     * i表示从第几行开始,n表示皇后数
     */
    private static int process(int i, int[] record, int n) {
        //如果当前的位置在i行,那么即表示i-1及之前的行的皇后一定是满足条件的,在摆第i行的皇后要满足条件不与之前的皇后共行、共列或共线
        //如果行数来到n,说明已经来到最后,此时即为出现一种摆法
        if(i == n){
            return 1;
        }

        int res = 0;
        //遍历列
        for (int j = 0; j < n; j++) {
            if(isValid(record,i,j)){//判断是否能摆
                record[i] = j;//能摆久记录摆下的皇后的列
                res += process(i+1,record,n);//递归,摆下一行,在下一行依旧遍历所有列
            }
        }
        return res;
    }

    //判断是否共行、共列、共斜线
    //由于record数组的索引存储的就是行数,因此不需要检查是否共行
    private static boolean isValid(int[] record, int i, int j) {
        for (int k = 0; k < i; k++) {
            //检查是否共列、共斜线(纵坐标之差 == 横坐标之差)
            if(j == record[k] || Math.abs(record[k] - j) == Math.abs(i-k)){
                return false;
            }
        }
        return true;
    }
}

上述最优解在n的值较大的时候跑出来仍是很慢,但无法对此进行结构上的优化,即无法进行时间复杂度的优化,但是可以使用位运算进行常数时间上的优化

优化

条件:不超过32皇后问题,超过32皇后问题需要把int转化为long类型

举个栗子

八皇后问题,n = 8

1位置不能放皇后,0位置可以

第1行00001000
列限制00001000
左斜线限制00010000
右斜线限制00000100
三个限制求或00011100
1
第2行01000000
第2行+第1行限制11101010

左斜线限制 = 列数 -  行差(左移)

右斜线限制 = 列数 + 行差(右移)

利用位运算的特性,限制哪些列可以放皇后,而不是每一列都遍历,节省时间

int pos = limit & (~(colLim | leftDiaLim | rightDiaLim));

第一个数表示前面的数,limit即前面都是0,后面8位都是1

limit011111111
列限制000001000
左斜线限制000010000
右斜线限制000000100
三种限制或000011100
~取反111100011
&并limit011100011

为什么要有limit?

因为可以和limit求并截去左侧的所有的数,在最终求得的pos数中,1的位置可以放置皇后,0的位置不可以放置皇后

mostRightOne = pos & (~pos + 1);
pos011100011
~pos100011100
~pos+1100011101
pos&(~pos+1)000000001

package algorithm;

public class NQueenOptimize {
    public static int num(int n) {
        //不超过32皇后问题
        if (n < 1 || n > 32) {
            return 0;
        }
        //生成一个二进制位数,后n位都是1,前面都是0
        //limit数本身的值不重要,只是用它的位信息
        int limit = -1;//n == 32
        if (n != 32) {
            limit = (1 << n) - 1;
        }
        return process(limit, 0, 0, 0);
    }

    /**
     * 1的位置不可以放皇后,0可以
     * colLim: 列的限制
     * leftDiaLim: 左斜线的限制
     * rightDiaLim: 右斜线的限制
     */
    private static int process(int limit, int colLim, int leftDiaLim, int rightDiaLim) {
        //列上的限制 == limit,说明全都放满了,此时即为一种摆法
        if (colLim == limit) {
            return 1;
        }

        /**
         * pos表示所有候选皇后的位置,1的位置可以放皇后,0的位置不可以放皇后
         * (colLim | leftDiaLim | rightDiaLim) 三种限制或
         * ~ 表示取反,此时在棋盘上1表示可以放皇后,0表示不能放皇后
         * & 和limit求与(0和1与为0,1和1与为1)
         */
        int pos = limit & (~(colLim | leftDiaLim | rightDiaLim));

        int res = 0;
        int mostRightOne = 0;
        
        //在每个1的位置上尝试皇后的位置,在尝试之后将值修改为0
        while (pos != 0) {
            mostRightOne = pos & (~pos + 1);
            pos = pos - mostRightOne;
            //左右限制变化
            res += process(limit,
                    colLim | mostRightOne,
                    (leftDiaLim | mostRightOne) << 1,
                    (rightDiaLim | mostRightOne) >> 1);
        }
        return res;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/218348.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入学习锁--Synchronized各种使用方法

一、什么是synchronized 在Java当中synchronized通常是用来标记一个方法或者代码块。在Java当中被synchronized标记的代码或者方法在同一个时刻只能够有一个线程执行被synchronized修饰的方法或者代码块。因此被synchronized修饰的方法或者代码块不会出现数据竞争的情况&#x…

Vue练习 v-model 指令在状态和表单输入之间创建双向绑定

效果&#xff1a; <template><h2>Text Input</h2><input v-model"text"> {{ text }}<h2>Checkbox</h2><input type"checkbox" id"checkbox" v-model"checked"><label for"checkbox…

使用VBA创建Excel条件格式

实例需求&#xff1a;数据总行数不确定&#xff0c;现需要将Category区域&#xff08;即C列到J列&#xff09;中第3行开始的区域设置条件格式&#xff0c;规则如下&#xff1a; 只对部分指定单元格应用色阶条件格式&#xff08;3色&#xff09;指定单元格应满足条件&#xff1…

抓取Chrome所有版本密码

谷歌浏览器存储密码的方式 在使用谷歌浏览器时,如果我们输入某个网站的账号密码,他会自动问我们是否要保存密码,以便下次登录的时候自动填写账号和密码 在设置中可以找到登录账户和密码 也可以直接看密码,不过需要凭证 这其实是windows的DPAPI机制 DPAPI Data Protection Ap…

微信小程序 纯css画仪表盘

刚看到设计稿的时候第一时间想到的就是用canvas来做这个仪表盘&#xff0c;虽然本人的画布用的不是很好但还可以写一写&#x1f600;。话不多说直接上代码。最后有纯css方法 <!--wxml--> <canvas canvas-id"circle" class"circle" >// js dat…

python pyaudio显示音频波形图

python pyaudio显示音频波形图 代码如下&#xff1a; import numpy as np import matplotlib.pylab as plb import wave# 读取 wav wf wave.open("./output.wav", "rb")# 获取音频相关参数&#xff1a;声道数、量化位数、采样频率、采样帧数 nchannels,…

Java多线程 - 黑马教程

文章目录 Java 多线程一、多线程概述二、 多线程创建方式1、继承 Thread 类创建线程2、实现 Runnable 接口3、实现 Callable 接口三、Thread 常用的方法四、线程安全什么是线程安全问题?线程安全问题出现的原因程序模拟线程安全五、线程同步线程同步方式1:同步代码块线程同步…

Opencv打开图片

cv.imread() oepncv中使用cv.imread函数读取图片&#xff0c;并打开窗口显示&#xff0c;以下是示例代码 import cv2 as cv import numpy as np from matplotlib import pyplot as pltsrc cv.imread("demo.jpg")#blue, green red cv.namedWindow("input ima…

GPIO的使用--时钟使能含义--代码封装

目录 一、时钟使能的含义 1.为什么要时钟使能&#xff1f; 2.什么是时钟使能&#xff1f; 3.GPIO的使能信号&#xff1f; 二、代码封装 1.封装前完整代码 2.封装结构 封装后代码 led.c led.h key.c key.h main.c 一、时钟使能的含义 1.为什么要时钟使能&#xff1f…

vue3 vue-cropper@next 实现图片裁切功能

Vue Cropper 实现上传图片预览&#xff0c;裁切上传效果 下载 pnpm add vue-croppernext使用 <template><inputref"inputRef"class"hidden"accept".png,.jpeg,.jpg"multipletype"file"change"handleUploadChange&quo…

C#,数值计算——计算实对称矩阵所有特征值和特征向量的雅可比(Jacobi)方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// Computes all eigenvalues and eigenvectors of /// a real symmetric matrix by Jacobis method. /// </summary> public class Jacobi { private …

CUDA简介——Grid和Block内Thread索引

1. 引言 前序博客&#xff1a; CUDA简介——基本概念CUDA简介——编程模式CUDA简介——For循环并行化 Thread Index&#xff1a; 每个Thread都有其thread index。 在Kernel中&#xff0c;可通过内置的threadIdx变量来获取其thread index。threadIdx为三维的&#xff0c;有相…

音频录制软件哪个好?帮助你找到最合适的一款

音频录制软件是日常工作、学习和创作中不可或缺的一部分。选择一个适合自己需求的录音软件对于确保音频质量和提高工作效率至关重要。可是您知道音频录制软件哪个好吗&#xff1f;本文将深入探讨两种常见的音频录制软件&#xff0c;通过详细的步骤指南&#xff0c;帮助您了解它…

记一次引入低版本包导致包冲突,表现为NoClassDefFoundError的故障

简而言之&#xff0c;因为参考别的项目处理excel的代码if(org.apache.poi.hssf.usermodel.HSSFDateUtil.isCellDateFormatted(cell)) &#xff0c;为了使用这个HSSFDateUtil类我引入了依赖&#xff1a; <dependency><groupId>org.apache.poi</groupId><a…

Python3 GUI 自制音乐播放器 图片浏览 图片轮播 PyQt5(附下载地址)

目录 Part1&#xff1a; 介绍 Part2: create window Part2: create window Adv Part4: Music Play Part5&#xff1a; 图片加载&#xff1a; Part1&#xff1a; 介绍 在这篇文章中&#xff0c;我们将学习如何使用PyQt 库创建一个基本的窗口应用程序&#xff0c;并进行一些…

【C/PTA —— 14.结构体1(课内实践)】

C/PTA —— 14.结构体1&#xff08;课内实践&#xff09; 6-1 计算两个复数之积6-2 结构体数组中查找指定编号人员6-3 综合成绩6-4 结构体数组按总分排序 6-1 计算两个复数之积 struct complex multiply(struct complex x, struct complex y) {struct complex product;product.…

1-4、调试汇编程序

语雀原文链接 文章目录 1、执行过程第一步&#xff1a;源程序第二步&#xff1a;编译连接第三步&#xff1a;执行 2、DOSBox运行程序第1步 进入EDIT.EXE第2步 编写源程序第3步 编译第4步 连接第5步 执行完整过程 3、DEBUG跟踪执行过程加载程序到内存执行程序debug和源程序数字…

Selenium 自动化高级操作与解决疑难杂症,如无法连接、使用代理等

解决 Selenium 自动化中的常见疑难杂症 这里记录一些关于 Selenium的常用操作和疑难杂症。 有一些细节的知识点就不重复介绍了&#xff0c;因为之前的文章中都有&#xff01; 如果对本文中的知识点有疑问的&#xff0c;可以先阅读我以前分享的文章&#xff01; 知识点&…

【滑动窗口】LeetCode2953:统计完全子字符串

作者推荐 [二分查找]LeetCode2040:两个有序数组的第 K 小乘积 本题其它解法 【离散差分】LeetCode2953:统计完全子字符串 题目 给你一个字符串 word 和一个整数 k 。 如果 word 的一个子字符串 s 满足以下条件&#xff0c;我们称它是 完全字符串&#xff1a; s 中每个字符…

【UGUI】sprite精灵的创建与编辑

如何切图&#xff08;sprite editor&#xff09; 有时候一张图可能包含了很多张子图&#xff0c;就需要在Unity 临时处理一下&#xff0c;切开&#xff0c;比如动画序列帧图集 虽然我们可以在PS里面逐个切成一样的尺寸导出多张&#xff0c;再放回Unity&#xff0c;但是不需要这…