(新手向)N皇后问题详解(DFS算法)

【N-Queen】N皇后问题(附完整C++代码) 问题分析 N皇后问题是比较经典的问题,它蕴含了回溯的思想,本文章利用回溯算法求解N皇后问题。 算法解析 ①本文章是逐行去搜索皇后的位置,每一行逐列检验该位置是否可以安放一个皇后,如果可以安放则记录列号;否则继续检索本行下一列。 for(int i=0;i<queenNum;i++){//一行中,逐列去检索 if(isAble(rowNum,i)){//检验该位置是否可以安放 column[rowNum] = i;//记录列号 findQueen(rowNum+1);//下一行对下 阅读详情

非常经典的一道题:

N皇后问题: 
国际象棋中皇后的势力范围覆盖其所在的行、列以及两条对角线,现在考察如下问题:如何在n x n的棋盘上放置n个皇后,使得她们彼此互不攻击 。

免去麻烦我们这里假定n不是很大。。

(图片来自百度百科(这是8皇后问题的一种解法))

某leetcode大犇曾说过:“这个问题和解数独题目有一个很大的共同点,那就是:我都不会。”

好了下面开始分析:(废话警告)

初步判断这问题的特点有:

1.有个场地来放置单位。

2.各个单位之间有制约。

3.没有特殊的数学方法,得把某一个摆法摆出来才能判断是否可行。

于是萌新一般都会这么想:对于1,:我搞个二维数组来存。对于2:我搞个判定函数来一个一个判定。对于3:我暴力枚举。

那么算法框架大概就是:我对二维数组的所有情况进行枚举,然后对每种情况进行判定

over ,输个数字n,按下回车,双手离开键盘,等了老半天发现命令提示符只有个光标在跳动 |

如果是在做网题,说不定就判定是超时或者内存溢出,过不了。

然后就开始思考怎么优化:

对于1,我可以缩减吗····,改成一维数组,,,似乎徒增麻烦。

对于2,我可以有更巧妙的判断方法吗?·············有个鬼,还不得把每个棋子的每一行每一列每两个斜线都瞅一下。

对于3,我一定要把所有情况都举出来嘛?···(于是脑子里面开始摆起了棋子,模拟算法过程)

然后就会发现  比如第一行前两个格子一开始就摆了两个相邻的棋子,诶这不明摆着皇后互怼了吗!后面还继续枚举就太傻了吧···

这种傻事情做了不是白白增加耗时吗!

所以就思考如何在这种“傻情况”出现的时候就pass掉后面所有情况。。。

于是脑子陷入了一团乱麻。。。

打住!

咱们换个思考方式,既然直接想有点困难,不如我们想办法先做点处理,让这些玩意儿便于我们把弄。

再回头想想规则,皇后可以吃掉所处的一行一列以及斜线上的棋子,那也就是说,每一行都最多只能有一个棋子,每一列都最多只能有一个棋子,

那我们不妨把每一行看成一组!

那么这一组就只有n个可能性(一行n个位置 每一次只有一个位置被占用)

也就是单个一行有n种可能性

因为有n行

哈哈那么就瞬间只需要讨论n*n种可能性了!

 还记得我们之前的思考吗?:

对于3,我一定要把所有情况都举出来嘛?···(于是脑子里面开始摆起了棋子,模拟算法过程)

     然后就会发现  比如第一行前两个格子一开始就摆了两个相邻的棋子,诶这不明摆着皇后互怼了吗!后面还继续枚举就太傻了吧···

   这种傻事情做了不是白白增加耗时吗!

   所以就思考如何在这种“傻情况”出现的时候就pass掉后面所有情况。。。

像这种情况:

(我的天这皇后画的...)

显然下面3,4,5····行都不用枚举了,直接pass掉

于是我们思路慢慢清晰了起来:

我们从第一行开始枚举,第一行第一格:

然后枚举第二行,也从第一格开始:

 判定一下,哇,不行,咋办呢?这情况下面所有行都没有枚举的必要了,但是本行还是可以继续的。。。于是我们开始枚举第二行第二个情况:

不行(斜线上互吃)。

继续第二行下一个情况:

行嘞!

那么我们就可以开第三行了:

不行(一列上吃)。

不行(斜线上吃)

 不行。

 还不行

 行嘞!

··················

好了,算法思路大概就出来了。

 我们就这样干下去,直到最后一行可行,那么我们就获得了一个可行解了,

然后我们想继续获得其他解,那么继续枚举下去,但是要退一步:

先从倒数第一行开始,我们枚举下一个,有解则输出,无解则继续。

倒数第一行结束了,咋办?

别忘了倒数第二行的情况还不一定枚举完了呢。

于是退到倒数第二行,继续如上操作。

··················


 干说着没用,撸代码:

#include<iostream>

using namespace std;
int main()
{
    return 0;
}

先准备好需要用的存储(这里用64个绰绰有余)

ans是用来存每一次的解 ans[1]表示第一行的那个元素的所在列的位置

#include<iostream>

using namespace std;
bool colMark[64] = { 0 };//元素所在列  如果有了元素在第k列 那么colMark[k]就标记上true
bool naMark[64] = { 0 };//捺,撇···顾名思义,表示元素所在的两个斜线o.o 原理同上
bool pieMark[64] = { 0 };
int total = 0;           //解的总个数
int N = 0;
int ans[64] = { 0 };
int main()
{
    return 0;
}

然后下面先写一个显示函数: 

void showOneSolution()//用来显示一个解
{
    total++;
    for (int i = 1; i<=N; ++i)
    {
        cout << ans[i] << " ";
    }
        cout << endl;
}

下面是核心:

void Dfs(int i)   //可以百度学习 深度优先搜索
{
    if (i > N)              //判断是否已经枚举完了N行 
    {
        showOneSolution();  //枚举完了就输出(此刻我们处于N+1行)
        return;             //返回到第N行
    }
    for (int j = 1; j <= N; ++j) //这里的j表示  本行的第j列
    {
        if ((!colMark[j])&&(!naMark[j-i+N])&&(!pieMark[i+j]))    //这里的"j-i+N"  "i+j"建议自己体会
        {          //判断这个格子所在的两个斜线和所在列是否为空
            colMark[j] = true;
            naMark[j - i + N] = true;
            pieMark[i + j] = true;
            ans[i] = j;
            Dfs(i + 1);
            colMark[j] = false;      //这个格子枚举完了要进入本行第j+1个格子(或者结束本行) 走之前别忘了恢复标记
            naMark[j - i + N] = false;
            pieMark[i + j] = false;
        }
    }
}

 最后组装起来:(当然啦,还是建议自己撸代码,你会发现很多意想不到的问题~解决问题的同时也是进步)

#include<iostream>


using namespace std;
bool colMark[64] = { 0 };
bool naMark[64] = { 0 };
bool pieMark[64] = { 0 };
int total = 0;
int N = 0;
int ans[64] = { 0 };
void showOneSolution()//用来显示一个解
{
    total++;
    for (int i = 1; i<=N; ++i)
    {
        cout << ans[i] << " ";
    }
        cout << endl;
}
void Dfs(int i)
{
    if (i > N)              //判断是否已经枚举完了N行
    {
        showOneSolution();  //枚举完了就输出(此刻我们处于N+1行)
        return;             //返回到第N行
    }
    for (int j = 1; j <= N; ++j) //这里的j表示  本行的第j列
    {
        if ((!colMark[j]) && (!naMark[j - i + N]) && (!pieMark[i + j]))
        {          //判断这个格子所在的两个斜线和所在列是否为空
            colMark[j] = true;
            naMark[j - i + N] = true;
            pieMark[i + j] = true;
            ans[i] = j;
            Dfs(i + 1);
            colMark[j] = false;      // 走之前别忘了恢复标记
            naMark[j - i + N] = false;
            pieMark[i + j] = false;
        }
    }
}
int main()
{
    cin >> N;
    Dfs(1);
    cout << total;
    system("pause");
    return 0;
}

总结:

思路混乱不妨换个角度理一理。

在纸上面画一画算法过程会有不少帮助。

代码少出错还是得多撸。

想什么呢?!撸代码!

N皇后问题——通俗易懂地讲解(C++) 注:参考程序猿小灰,hackbuteer1 八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出: 在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上 (斜率为1),问有多少种摆法。高斯认为有76种方案。 让我们来举个栗子,下图的绿色格子是一个皇后在棋盘上的“封锁范围”,其他皇后不得放置在这些... 阅读详情

相关推荐

深度优先算法解决“八皇后问题”

“八皇后问题”以及“n 皇后问题”的深度优先(Depth First Search, DFS)算法解法,C++ 语言。

#include 4290

acwing-843.n-皇后问题

题目描述 n−皇后问题是指将 n 个皇后放在 n×n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。 现在给定整数 n,请你输出所有的满足条件的棋子摆法。 输入格式 共一行,包含整数 n。 输出格式 每个解决方案占 n 行,每行输出一个长度为 n 的字符串,用来表示完整的棋盘状态。 其中 . 表示某一个位置的方格状态为空,Q 表示某一个位置的方格上摆着皇后。 每个方案输出完成后,输出一个空行。 注意:行末不能有多余空格。 输出方案的顺序任意,只要不重复且没有

weixin_43211195的博客 1599

N皇后问题 DFS C++

N皇后问题 N皇后问题研究的是如何将N个皇后放置在N * N的棋盘上,并且使皇后彼此不能相互攻击。(皇后可以直走,横走,斜走) 这里使用DFS来解决这道问题,用递归搜索所有的可能性,把符合要求的解存放在数组queenPos中,这个数组下标代表行数,对应的值代表列数。如queenPos[0]值为1,就代表皇后摆放在(0,1)这个位置。 #include&amp;amp;lt;iostream&amp;amp;gt; #i...

qq_41697164的博客 2272

【算法问题】N 皇后问题

本文介绍了 N 皇后问题的相关知识。

代码星辰的博客 4973

c语言 dfs n皇后问题 深度优先搜素

c语言dfs基础入门题目 n皇后问题 n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行、同一列或同一斜线上。 现在给定整数n,请你输出所有的满足条件的棋子摆法。 输入格式 共一行,包含整数n。 输出格式 每个解决方案占n行,每行输出一个长度为n的字符串,用来表示完整的棋盘状态。 其中”.”表示某一个位置的方格状态为空,”Q”表示某...

king_fdy的博客 2009

第四:搜索算法应用 - 四皇后问题

四皇后问题 在 n 行 n 列的国际象棋上摆放 n 个皇后,使其不能互相攻击(即任意两个皇后都不能处于同一行、同一列或同一斜线上)。请问有多少种摆法,以及如何摆放这些皇后。这就是经典的 n 皇后问题。如下图所示: 当 n=4 时就成为了四皇后问题。很明显,这种问题我们可以通过搜索技术来进行求解,例如深度优先搜索。 用回溯法,在构建解空间树的途中进行深度优先探索,当探索到某一种棋盘局部不是四皇后问题的解的时候(比如出现任意两个或两个以上的棋子在同一行/同一列/45度斜线上),就可以判断这个节点向下派生出的解

炫云云 3017

【算法基础】DFS深度优先算法 —— AcWing 843. n-皇后问题 AcWing 842. 排列数字

Acwing算法基础课笔记 题解 AcWing 843. n-皇后问题 AcWing 842. 排列数字

Remember who you are! 5426

新手避坑指南:用PIC16F15355开发板和MCC完成第一个UART通信项目

本文为新手提供了使用PIC16F15355开发板和MPLAB代码配置器(MCC)实现首个UART通信项目的完整指南。通过图形化配置系统时钟、UART参数并自动生成驱动代码,手把手教学如何避开常见陷阱,快速完成从环境搭建、代码编写到调试输出的全流程,助力开发者高效入门PIC单片机开发。

bash7scripter的博客 725

DFS(深度优先搜索算法)

1.dfs基本思想 dfs:深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或搜索树或图的算法.沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索。简单来说dfs可以看作是一个执着的人,优先往下走。搜索方式如图: 2..

zgdlxs的博客 4万+

从T型结到Wilkinson:5分钟搞懂功分器选型指南(附最新射频测试数据对比)

本文通过对比T型结、电阻型和Wilkinson三种功分器的核心原理与实测数据,提供了清晰的射频功分器选型指南。文章结合最新的2.4GHz ISM频段测试数据,分析了插入损耗、回波损耗和端口隔离度等关键指标,并针对窄带物联网、射频测试及合成系统等不同应用场景,给出了具体的选型建议和实战提醒,帮助工程师根据系统需求做出最优决策。

bush的博客 305

零基础实战:YOLO检测头自定义替换全攻略

本文为零基础用户提供了YOLO检测头自定义替换的完整实战指南。通过将检测头比作汽车的“方向盘”,文章详细阐述了为何需要替换、如何寻找和集成新检测头模块、修改配置文件以及最终训练验证的全过程,旨在帮助用户针对特定任务(如小目标检测)提升模型性能。

perl8的博客 255

每日一题:解决N皇后问题的深度优先搜索(DFS)算法详解

N皇后问题是经典的算法问题之一,要求在N×N的棋盘上放置N个皇后,使得它们互不攻击。具体来说,任何两个皇后不能在同一行、同一列或同一对角线上。本文将详细介绍如何使用深度优先搜索(DFS)算法来解决N皇后问题,并提供一个完整的C++实现。

m0_59246703的博客 1597

泛微OA与金蝶云星空审批流程对接实战:从报销单到采购合同的完整指南

本文详细介绍了泛微OA与金蝶云星空审批流程的深度集成方案,涵盖从报销单到采购合同的完整对接指南。通过API层面的无缝连接,实现流程自动化、数据同源和权限联动,显著提升企业业务效率。文章还提供了环境配置、数据映射、接口安全等实用技巧,助力企业轻松完成系统对接。

weixin_29268637的博客 245

DFS(深度优先遍历、N皇后问题、2N皇后问题)

尽管在很多情况下回溯法和DFS是紧密相关的,但它们并不总是等价的。回溯法更侧重于问题的求解策略,而DFS更侧重于图的遍历策略。然而,在实际应用中,这两个概念经常交织在一起。

走在努力路上的自己的博客 2513

基于ST32 DAC7311数模转换器驱动代码及电路设计完整版

基于ST32的DAC7311模数转换器的电路设计及驱动代码完整版

qq_39626643的博客 3720

张正友标定法_单目-线激光三维扫描系统中光刀平面的标定

单目-线激光三维扫描系统中光刀平面的标定线结构光有结构简单、精度高、测速快等特点,被广泛应用于三维重建领域。线结构光三维扫描系统由一个相机和一个线结构光投射器构成,线结构光投射器将线结构光投射到被测物体表面,相机采集带有线激光的被测物体图像,根据相机和线激光投射器间的相对位置关系,使用激光三角法计算出激光线上的点在相机坐标系下的坐标。激光三角法原理如下图所示,线激光投射的扇形区域可以看作是一个平面...

weixin_39616379的博客 1074

DFS (深度优先算法)

DFS(深度优先搜索算法):一种用于遍历或者树或者图的算法,是一种递归程序,不断递归达到无法在到达的点,简单点来说:一条路一直走,走到没有路后就原路返回,重新选择另一条 dfs(step + 1)。 DFS = 暴搜 + 回溯算法 + 剪枝(大多数是这样)。DFS需要回溯算法,其他算法也需要回溯算法,两种是一种调用关系。 暴搜:一条路走到黑(直接递归走到底) 回溯:DFS开启另一条路则需要回溯,如果暴搜那条路找不到答案就要回溯走另外一条道路。 剪枝:如果明确接下来的搜索找不到答案或者不是最优解,就

qq_46056407的博客 4730

AD18 PCB模块的Copy

在PCB布局时,时常会将元器件先分模块进行排布,最后才会进行总体的布局,在局部布局的时候,想要移动一个模块的器件总是很麻烦,需要选中全部才能进行移动,有些时候还有选漏的情况,所以会将局部布局的模块把它看做一个整体进行移动,效果如下,元件,布线,铜皮,过孔以及元件编号的位置摆放都和源模块一模一样。4、再选中需要复用的模块内的元件,按照第3步的顺序排序,粘贴刚刚复制的Channel Offset参数。在PCB布局时,有多个模块原理图是一模一样的情况,我们可以只画一个模块,之后灵活应用模块,进行copy。

qq_53859658的博客 3238

深入浅出,详解深度优先搜索(DFS)

本文将从原理出发,结合例子深入浅出地讲解深度优先搜索

浪里小白龙nbw的博客 2万+

科研绘图系列:R语言绘制极坐标饼图(pie plot)

科研绘图系列:R语言极坐标饼图(pie plot)

专注生信领域 1053

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

数据结构_dfs深度优先算法入门(C语言)

数据结构_dfs深度优先算法入门(C语言) 文章目录数据结构_dfs深度优先算法入门(C语言)0.闲话1.个人理解2.全排列问题(1到n的排列组合)2.八皇后问题求解二维迷宫(1)只输走出迷宫解的个数(2)输出解的个数和路径 0.闲话 ​ 才学习数据结构的dfs,做一下笔记记录一下,加深理解-.- ​ 我这里就简单讲一下我的理解和一下例子 ​ 推荐学习资源(B站视频,原理和实例): 洛谷 普及组...

qq_35289660的博客 5299

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

python DFS深度优先搜索及N皇后问题求解

DFS可谓是算法里的一个大头,不懂DFS都不敢承认自己学过数据结构。今天菜鸡我要逆袭了,先从经典的N皇后问题搞起,试试DFS水深几尺【略加思索】 内容篇幅有点长,不想看我对DFS嗷嗷叫的朋友还是直接去见皇后吧~ 1. 对DFS的理解 2.N皇后问题 1. 对DFS的理解 解决这个问题前,先来回顾下DFS究竟是何方神圣 `<" - ">` DFS——depth f...

weixin_42194402的博客 1890

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

(DFS)深度优先搜索算法详解

背景 DFS 英文全称为(Depth First Search),中文简称深度优先搜索算法,其过程为沿着每一个可能的路径向下进行搜索,直到不能再深入为止,并且每一个节点只能访问一次。 算法的搜索遍历图的步骤 (1)首先找到初始节点A, (2)依此从A未被访问的邻接点出发,对图进行深度优先遍历 (3)若有节点未被访问,则回溯到该节点,继续进行深度优先遍历 (4)直到所有与顶点A路径想通的节点都被访问过一次 举个例子,在下方的无向连通图中,假设我们要从起始点A出发,使用深度优先搜索算法进行搜..

202xxx的博客 3万+

DFS深度优先搜索

一、DFS的概念 {DFS的定义 DFS的搜索方式 DFS采用的数据结构 DFS的特点} 二、DFS的实战应用 {1.排列数字 2.n-皇后问题}

咸鱼势力登场 1万+

[算法]八皇后问题

每个格子有一一对应的行,列, (列,行),记作(x,y)试规定以左下角格子为(1,1)向右延伸为(1,2), (1,3),向下延伸为(2,1), (3,1)第可以理解为第y行第x列,那么对角线可以表示为主对角线x-y=0(下图绿线),则副对角线为 x+y = 9,还有一点,棋盘为八行八列,放置八皇后,若解,则表明,每列,每行均有皇后,我们考虑放置第x列的皇后,应该放置在行数,若该格点,并未被其他皇后攻击,则放置皇后,并标记各个变量,那么知道一点坐标,便可以标识该对角线上所有的点。:这时棋盘的大小变为。

qq_57916921的博客 1294

LeetCode琅琊榜第十三层-全排列(DFS深度优先算法)

LeetCode.46全排列 难度:中等 博主空间与往期力扣 题目链接

算法萌新一枚 804
上一篇: N皇后问题的二进制优化详细思路
下一篇: 巧用组合数证明平方和、立方和
咖啡咖_CoffCa
博客等级 码龄6年 116粉丝 58原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖啡咖_CoffCa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值