n皇后 - 位运算版

article/2025/10/14 3:44:51

 n皇后问题是大家在递归里会碰到的一个经典问题。以前高中我学DFS的时候,老师首先让我看的就是八皇后。

不过这皇后的时间复杂度大家可想而知了。而接下来的位运算将这个效率重新提到一个高度。

我是以前在Matrix67大牛那里学的,最近数据结构实验刚好碰到n皇后,就在这里“复述”一遍吧。

Code:
  1. void doans(int r, int ld, int rd)  
  2. {  
  3.     if(r != uplimit)  
  4.     {  
  5.         int pos = uplimit & ~(r | ld | rd);  
  6.   
  7.         while(pos != 0)  
  8.         {  
  9.             int p = pos & (~pos + 1);  
  10.             pos -= p;  
  11.             doans(r + p, (ld + p) << 1, (rd + p) >> 1);  
  12.         }  
  13.     }  
  14.     else sum++;  
  15. }  

乍一看有点模糊吧?没错,这就是n皇后的递归函数了。我们一个个来解析。

首先uplimit是(1 << n) - 1,如果n是8的话uplimit就是255,看做二进制就是11111111。聪明的人一看就知道了,这里每一位就代表一个皇后。

而r代表每一列能放与否,如10001110就代表第2、3、4、8个能放。

所以开始一个if来判断皇后放齐了没。如果齐了,显然r也要等于11111111。

还有ld和rd分别是对角线的各位能放与否。

我们来看看下图(From Matrix67):

  

假设我们已经递归到第三行了(左图),这里可以看出r为101010也就是说二、四、六可以放。ld是100100(蓝色线),二、三、五、六可以放,rd为000111,。

好的,那么哪几个可以放呢?我们将r、ld、rd或运算一遍(或者r有或者ld有或者rd有),得到101111,也就是说这三个合起来的话就只能放第二格了。然后我非运算一遍,得到的是010000,非运算之后1代表可以放,0代表不可以放了。然后我们再与运算一遍就得到可以放的位置了:010000。

下一步,如果能放的位置不是0的话我们就开始放:

Code:
  1. int p = pos & (~pos + 1);  

这一句我们可以用

Code:
  1. int p = pos & -pos;  

来代替,什么意思呢?其结果是取出最右边的那个1。比如我们有一个数字pos是10010,那么p得到的结果就是10了。那么上面那个010000得到的结果就是10000了。然后我们更新一遍pos:让它减去p也就是10000,那么pos得到的结果就是000000。也就是说下一次循环就跳出了。

好的,我们不管下一次循环,我们讲怎么进入下一层递归:

看看传进去的三个参数:

r + p为下一层递归的r,即10000 + 101010 = 111010那就相当于放进第二个了。

(ld + p) << 1为下一层的ld,即(100100 + 10000) << 1为(110100) << 1也就是1101000了。当然,在下一层递归的时候第一个1将会被uplimit & ~(r | ld | rd)截掉成为101000。

(rd + p) >> 1为下一层的rd,即(000111 + 10000) >> 1为(010111) >> 1也就是001011。

那么在新的一层里又有新的r和ld还有rd组合了。

主题的思路就是这样子的。

 

最后方便大家理解学习,发下我的n皇后代码:

Code:
  1. /** 
  2.  * @brief n皇后问题 - 位运算版 
  3.  * @Author 朱凯迪 
  4.  * 2010/11/22 
  5.  */  
  6. #include <iostream>  
  7. #include <list>  
  8. using namespace std;  
  9.   
  10. /** 方案链表 */  
  11. list<int> sol;  
  12.   
  13. /** 棋盘大小 */  
  14. int n;  
  15. /** 棋盘摆满时的数字 */  
  16. int uplimit;  
  17.   
  18. void print()  
  19. {  
  20.     printf("/n");  
  21.     list<int>::iterator i;  
  22.     for(i = sol.begin(); i != sol.end(); i++)  
  23.     {  
  24.         int tmp = *i, cnt = 0;  
  25.         while(tmp != 1)  
  26.         {  
  27.             cnt++;  
  28.             tmp = tmp >> 1;  
  29.         }  
  30.         for(int j = 0; j < cnt; j++) printf("■");  
  31.         printf("○");  
  32.         for(int j = cnt + 1; j < n; j++) printf("■");  
  33.         printf("/n");  
  34.     }  
  35.     printf("/n");  
  36. }  
  37.   
  38. void doans(int r, int ld, int rd)  
  39. {  
  40.     if(r != uplimit)  
  41.     {  
  42.         /** 还没摆满 */  
  43.   
  44.         /** 取能放的位置 */  
  45.         int pos = uplimit & ~(r | ld | rd);  
  46.   
  47.         /** 若还有位置如00001011表示能放5、7、8位 */  
  48.         while(pos != 0)  
  49.         {  
  50.             /** 取低位 */  
  51.             int p = pos & (~pos + 1);  
  52.   
  53.             /** 更新位置 */  
  54.             pos -= p;  
  55.   
  56.             /** 答案入 */  
  57.             sol.push_back(p);  
  58.   
  59.             /** 更新禁手并进行下一层更新 */  
  60.             doans(r + p, (ld + p) << 1, (rd + p) >> 1);  
  61.   
  62.             /** 答案出 */  
  63.             sol.pop_back();  
  64.         }  
  65.     }  
  66.     else print();  
  67. }  
  68.   
  69. int main()  
  70. {  
  71.     while(cin >> n)  
  72.     {  
  73.         /** 如n为8,则uplimit为11111111 */  
  74.         uplimit = (1 << n) - 1;  
  75.         doans(0, 0, 0);  
  76.     }  
  77.   
  78.     return 0;  
  79. }  

 

 


http://chatgpt.dhexx.cn/article/n4R964VT.shtml

相关文章

n皇后最快算法详解

n皇后问题再经典不过了&#xff0c;想必大家也听说过。 再简单说一下吧&#xff0c;就是一个n*n的棋盘&#xff0c;放置n个皇后&#xff0c;使得竖着不攻击&#xff0c;横着不攻击&#xff0c;斜着不攻击。求有多少种方法。 &#xff08;国际象棋不是这么玩的呀 &#xff09; …

51. N 皇后

51. N 皇后 按照国际象棋的规则&#xff0c;皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方…

51. N皇后

51. N皇后 https://leetcode-cn.com/problems/n-queens/ 四皇后的解 n个皇后&#xff0c; nn 的棋盘上 根据要求 每行有且仅有一个皇后&#xff08;如果有一行没有那么必有一行至少两个皇后&#xff0c;不符合&#xff09; 递归回溯&#xff0c;每次尝试在一行中摆放皇后&…

递归算法——n皇后

** 递归算法——n皇后 ** n皇后问题&#xff1a; 输入整数n&#xff0c;要求n个国际象棋的皇后&#xff0c;摆在n*n的棋盘上&#xff0c;互相不能攻击&#xff0c;输出全部方案。 输入&#xff1a; 输入一个正整数N。 输出&#xff1a; 程序输出N皇后问题的全部摆法。 行里…

kettle连接mysql教程_KETTLE初学者使用教程

Kettle的建立数据库连接、使用kettle进行简单的全量对比插入更新:kettle会自动对比用户设置的对比字段,若目标表不存在该字段,则新插入该条记录。若存在,则更新。 Kettle简介:Kettle是一款国外开源的ETL工具,纯java编写,可以在Window、Linux、Unix上运行,数据抽取高效稳…

Kettle Spoon 安装配置详解

文章目录 1 概述2 安装2.1 软件下载2.2 JDK 环境变量配置2.3 数据库驱动包下载2.4 双击 Spoon.bat 启动 3 简单使用3.1 transformation 转换3.1.1 文件 - 新建 - 转换3.1.2 核心对象 - 输入 - 表输入3.1.3 核对对象 - 输出 - 插入/更新3.1.4 保存 - xxx.ktr 3.2 job 作业3.2.1 …

Spoon安装步骤

主数据库连接步骤 主对象树点击转换&#xff0c;双击DB连接 配置信息完成后点击测试成功 二&#xff0e;源数据库连接步骤 1.点击Connect,点击other repositories 2.点击Database Repository 编辑名称&#xff08;注意必须用英文&#xff09; 再点击数据库连接 配置选项 …

kettle下载安装使用教程

Kettle简介 Kettle是一款国外开源的ETL工具&#xff0c;纯java编写&#xff0c;可以在Window、Linux、Unix上运行&#xff0c; 数据抽取高效稳定。Kettle 中文名称叫水壶&#xff0c;该项目的主程序员MATT 希望把各种数据放到一个壶里&#xff0c;然后以一种指定的格式流出。K…

KETTLE使用教程

Kettle的建立数据库连接、使用kettle进行简单的全量对比插入更新&#xff1a;kettle会自动对比用户设置的对比字段&#xff0c;若目标表不存在该字段&#xff0c;则新插入该条记录。若存在&#xff0c;则更新。 Kettle简介&#xff1a;Kettle是一款国外开源的ETL工具&#xff0…

spoon mysql教程_kettle 教程(一):简介及入门

介绍 kettle 是纯 java 开发&#xff0c;开源的 ETL工具&#xff0c;用于数据库间的数据迁移 。可以在 Linux、windows、unix 中运行。有图形界面&#xff0c;也有命令脚本还可以二次开发。 安装 这边以 windows 下的配置为例&#xff0c;linux 下配置类似。 jdk 安装及配置环境…

kettle基础使用教程

文章目录 前言一、下载、安装二、启动软件三、转换的使用教程四、作业的使用教程总结 前言 Kettle简介&#xff1a;Kettle是一款国外开源的ETL工具&#xff0c;纯java编写&#xff0c;可以在Window、Linux、Unix上运行&#xff0c;数据抽取高效稳定。Kettle 中文名称叫水壶&…

ETL工具-Kettle Spoon教程

转自&#xff1a;https://blog.csdn.net/liaomin416100569/article/details/82798879 一 。Kettle Spoon简介 ETL&#xff08;Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程&#xff09;&#xff0c;对于企业或行业应用来说&#xff0c;我们经常会遇…

KETTLE 使用教程

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 Kettle的建立数据库连接、使用kettle进行简单的全量对比插入更新&#xff1a;kettle会自动对比用户设置的对比字段&#xff0c;若目标表…

spoon mysql教程_Kettle-Spoon入门示例

Spoon 是Kettle的设计调试工具 1.驱动: a) 驱动错误 b) 驱动添加 2.端口错误&#xff1a;连接数据库端口不对 3.正常连接 4.表输入 a) 新建一个表输入&#xff0c;获取数据库表的数据 b) 预览数据 c) 当前表数据输出到另外一个同样的表 d) 当前表数据输出到另外一个同样的表 e)…

数据库转换工具 spoon使用

由于项目需求 需要把oracle数据库转换为mysql数据库&#xff0c;所以使用spoon转换&#xff0c;简单快捷 ETL Kettle Spoon简介 ETL&#xff08;Extract-Transform-Load的缩写&#xff0c;即数据抽取、转换、装载的过程&#xff09;&#xff0c;对于企业或行业应用来说&#…

spoon mysql教程_spoon新手入门教程

Kettle是一款国外开源的ETL工具&#xff0c;纯java编写&#xff0c;可以在Window、Linux、Unix上运行&#xff0c;数据抽取高效稳定。Kettle 中文名称叫水壶&#xff0c;该项目的主程序员MATT 希望把各种数据放到一个壶里&#xff0c;然后以一种指定的格式流出。Kettle这个ETL工…

Kettle工具简单使用(spoon)

1、添加测试数据 在navicat中随便找个表当做被转化的数据进行测试&#xff0c;以下表为例&#xff1a; 在SQL server数据库中创建表 2、下载spoon软件 下载路径&#xff1a;https://download.csdn.net/download/qq_57404736/85013576 打开文件夹&#xff0c;双击spoon.ba…

Spoon工具的使用

Spoon工具的使用 第一步 建立中间表 create table table_name ( code varchar(100), name varchar(100) )第二步 新建转换 在核心对象 输入中找到表输入双击&#xff0c; 输出中找到表输出双击 第三步&#xff0c;双击表输入进入该界面 点新建进入如下界面 填写信息后点T…

spoon入门教程

Kettle是一款国外开源的ETL工具&#xff0c;纯java编写&#xff0c;可以在Window、Linux、Unix上运行&#xff0c;数据抽取高效稳定。Kettle 中文名称叫水壶&#xff0c;该项目的主程序员MATT 希望把各种数据放到一个壶里&#xff0c;然后以一种指定的格式流出。Kettle这个ETL工…

Spoon工具使用(kettle进行实时同步数据)

文章目录 Spoon工具使用&#xff08;kettle进行实时同步数据&#xff09;安装相关概念转换DB连接步骤和节点连接 作业DB连接作业项目 Spoon工具使用&#xff08;kettle进行实时同步数据&#xff09; 安装 解压完Spoon安装包后&#xff0c;双击.bat文件打开 相关概念 转换…