算法学习笔记之三:八皇后问题(递归、回溯)

article/2025/9/15 8:09:20

(一)题记

从去年下半年开始找工作,大大小小也被“鄙”试、“面”试了n多回了。说实话只怪自己并未对常见的笔试题、面试题进行准备,导致败下阵来。一门学问要想学透学精是需要时间的,慢慢来吧……

第一次听到“八皇后”问题是在参加百度计算机视觉算法工程师面试时听中科院来面试的一个博士说的,当时隐约记得他是搞机器学习、模式识别的,所以自己以为这是很难的一个问题,回来简单想了一下也就没有细究。到后来去本行业初创公司“春雨”面试的时候,面试官让当场码代码解决这个问题,由于之前有印象,就定式思维地一直以为很难,所以从开始内心有些许的恐惧,最后在面试官的提示下写了个大概,最终结果不是很令人满意。

废话不多说了,一句话“不要被思维定式所困扰“,其实很简单的一个问题。

下面直奔主题:

(二)问题

http://zh.wikipedia.org/wiki/八皇后问题

八皇后问题是一个以国际象棋为背景的问题:如何能够在 8×8 的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n当且仅当 n = 1 或 n ≥ 4 时问题有解。

(三)思路分析

其实该问题并不难,利用递归方法很容易解决。没放置一个皇后,就将其能够攻击的区域进行标记,然后放置下一个皇后,一次类推……;此外,如果有解最终肯定是每一行有且只有一位皇后,所以放置的时候按照逐行放置的顺序进行。此问题难点在于如何把控递归函数的返回条件,一种条件是8个皇后放置完成后,返回成功,一种条件是该行中已经没有可以放置的位置,此时返回失败,需要重新放置。此时要额外注意,所谓的“重新放置”指的并不是将所有皇后清除重新来过,而是只返回上一层,将上一个导致本次放置失败的皇后进行清除,然后重新更新其位置,通过逐级放置、或逐级回溯可以达到遍历所有情况找到所有解(下文中给出的自己的代码的计算结果不是独立解的个数,而是所有可行解的情况)

(四)自己码代码

//--------------------------------------
//利用函数递归,解决八皇后问题
//
//	zssure	2014-03-12
//--------------------------------------#include <stdio.h>
#include <cmath>int count=0;//全局计数变量/*--------------------四个皇后----------------------*/
//#define QUEEN_NUM 4
//int label[QUEEN_NUM][QUEEN_NUM]={	0,0,0,0,	
//									0,0,0,0,
//									0,0,0,0,
//									0,0,0,0	};/*--------------------五个皇后----------------------*/
//#define QUEEN_NUM 5
//int label[QUEEN_NUM][QUEEN_NUM]={	0,0,0,0,0,
//									0,0,0,0,0,
//									0,0,0,0,0,
//									0,0,0,0,0,
//									0,0,0,0,0		};/*--------------------六个皇后----------------------*/
//#define QUEEN_NUM 6
//int label[QUEEN_NUM][QUEEN_NUM]={	0,0,0,0,0,0,
//									0,0,0,0,0,0,
//									0,0,0,0,0,0,
//									0,0,0,0,0,0,
//									0,0,0,0,0,0,
//									0,0,0,0,0,0
//													};/*--------------------七个皇后----------------------*/
//#define QUEEN_NUM 7
//int label[QUEEN_NUM][QUEEN_NUM]={	0,0,0,0,0,0,0,
//									0,0,0,0,0,0,0,
//									0,0,0,0,0,0,0,
//									0,0,0,0,0,0,0,
//									0,0,0,0,0,0,0,
//									0,0,0,0,0,0,0,
//									0,0,0,0,0,0,0
//													};/*--------------------八个皇后----------------------*/
#define QUEEN_NUM 8
int label[QUEEN_NUM][QUEEN_NUM]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};void FillChessbox(int m,int n,int num)
{for(int i=0;i<QUEEN_NUM;++i)for(int j=0;j<QUEEN_NUM;++j)if(abs(i-m)==abs(j-n))//对角区域填充{if(label[i][j]==0)label[i][j]=num;}int i=0,j=0;while(i<QUEEN_NUM)//行填充{if(label[i][n]==0)label[i][n]=num;++i;}while(j<QUEEN_NUM)//列填充{if(label[m][j]==0)	label[m][j]=num;++j;}}
void ClearChessBox(int m,int n,int num)
{for(int i=0;i<QUEEN_NUM;++i)for(int j=0;j<QUEEN_NUM;++j)if(abs(i-m)==abs(j-n) && label[i][j]==num)label[i][j]=0;int i=0,j=0;while(i<QUEEN_NUM){if(label[i][n]==num)label[i][n]=0;++i;}while(j<QUEEN_NUM){if(label[m][j]==num)label[m][j]=0;++j;}
}
void AllClear()
{for(int i=0;i<QUEEN_NUM;++i)for(int j=0;j<QUEEN_NUM;++j)label[i][j]=0;}
void PrintResult()
{for(int i=0;i<QUEEN_NUM;++i){for(int j=0;j<QUEEN_NUM;++j)printf("%d ",label[i][j]);printf("\n");}
}
bool EightQueen(int n/*皇后个数*/,int c/*已经放置的皇后个数*/)
{//static int count=0;//小于3x3的棋盘是无解的if(n<4)return false;for(int i=0;i<n;++i){if(label[c-1][i]==0)//存在可以放置第c个皇后的位置{label[c-1][i]=c+1;if(c==n)/*已经放置完毕所有的皇后*/{++count;PrintResult();printf("**************************\n");ClearChessBox(c-1,i,c+1);//AllClear();return true;}FillChessbox(c-1,i,c+1);EightQueen(n,c+1);ClearChessBox(c-1,i,c+1);/*-------------------------------------------------------------------------------------------------------------------------//	现场恢复,无论下一个皇后是否顺利放置,都应该恢复现场。原因是////	如果下一个皇后放置失败,那么自然应该将本次放置的皇后去除,重新放置,所以需要进行现场恢复(即回溯);//	如果下一个皇后放置成功,意味着本次放置已经满足条件,是一个解,此时需要恢复现场,进行下一次的重新放置,寻找下一个解。////------------------------------------------------------------------------------------------------------------------------*///if(!EightQueen(n,c+1))//	ClearChessBox(c-1,i,c+1);}}return false;
}int main()
{EightQueen(QUEEN_NUM,1);printf("%d\n",count);return 0;
}
【注】:本次的代码使用了二维数组来标记皇后的位置,且最后输出结果中皇后位置并未准确显示,还有待改进。
参考博文:

http://blog.csdn.net/feixiaoxing/article/details/6877965

http://blog.csdn.net/sandyzhs/article/details/4250563


Author:zssure

E-mail:zssure@163.com

Date:2014-03-12


http://chatgpt.dhexx.cn/article/0u4GcgUG.shtml

相关文章

【算法模板】dfs 八皇后问题

1.前言 本文将以经典的八皇后问题来解析dfs的主要思想。 2.题目 题目出处&#xff1a;活动 - AcWing 3.思路讲解 dfs的思想暗含树的历遍&#xff0c;主要步骤为&#xff1a; 判断是否搜索完毕---历遍寻找符合条件的元素---递归进入下一层搜索---还原现场 我们可以先分析这个问题…

八皇后递归算法

八皇后问题 &#xff1a;假设 將八个皇后放到国际象棋盘上&#xff0c;使其两两之间无法相互攻击。共有几种摆法&#xff1f; 基础知识&#xff1a; 国际象棋里&#xff0c;棋盘为8X8格。 皇后每步可以沿直线、斜线 走任意格。 思路&#xff1a; 1.想把8个皇后放进去&…

算法设计(一) : 搜索算法实现八皇后问题

写在开头&#xff1a;实验结果截图8皇后太多截不完&#xff0c;用4皇后代替了&#xff0c;只需将n->8就行 目录 写在开头&#xff1a;实验结果截图8皇后太多截不完&#xff0c;用4皇后代替了&#xff0c;只需将n->8就行图解算法过程&#xff1a;算法一&#xff1a;DFS 按…

八皇后问题(递归回溯算法详解+C代码)

为了理解“递归回溯”的思想&#xff0c;我们不妨先将4位皇后打入冷宫&#xff0c;留下剩下的4位安排进4x4的格子中且不能互相打架&#xff0c;有多少种安排方法呢&#xff1f;现在我们把第一个皇后放在第一个格子&#xff0c;被涂黑的地方是不能放皇后的&#xff1a; 第二行的…

算法设计与分析——八皇后问题的实现——代码分析和讲解

文章目录 题目描述思路分析回顾回溯法的基本框架解题框架应用到本题定义问题的解空间定义约束函数模仿回溯法的框架去解决问题 实现源码分析与总结 题目描述 在88格的棋盘上放置彼此不受攻击的8个皇后。国际象棋的规则&#xff1a;皇后可以攻击与之处在同一行或同一列或同一斜…

八皇后问题算法(C语言实现)

1. 八皇后的由来和问题 八皇后问题&#xff0c;是一个古老而著名的问题&#xff0c;是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯贝瑟尔于1848年提出&#xff1a;在88格的国际象棋上摆放八个皇后&#xff0c;使其不能互相攻击&#xff0c;即任意两个皇后都不能处于同一…

八皇后算法解析

今天研究力扣的一道题死活写不出来对应的算法&#xff0c;没办法自己算法基础太差。于是看了下答案&#xff0c;发现使用什么回溯算法&#xff0c;菜鸟表示平时开发期间写的最复杂的程序就是写了两层for循环&#xff0c;已经很牛逼了有木有&#xff1f;这个回溯算法什么鬼&…

递归算法之八皇后问题

八皇后问题&#xff08;英文&#xff1a;Eight queens&#xff09;&#xff0c;是由国际象棋棋手马克斯贝瑟尔于1848年提出的问题&#xff0c;是回溯算法的典型案例。 问题表述为&#xff1a;在88格的国际象棋上摆放8个皇后&#xff0c;使其不能互相攻击&#xff0c;即任意两个…

八皇后问题4种c语言算法

八皇后问题 1.递归回溯法 B站懒猫老师讲的&#xff08;我在这里学的&#xff09; 八皇后问题的递归回溯算法思路&#xff1a;从第一行开始当某一行皇后位置不与前面所有皇后位置冲突那么记录该行皇后位置并调用递归函数进入下一行&#xff0c;摆放下一个皇后&#xff0c;逐个…

数据结构与算法 — 八皇后问题(回溯算法)

问题描述 在88格的国际象棋上摆放8个皇后&#xff0c;使其不能互相攻击&#xff0c;即任意两个皇后都不能处于同一行、同一列或同一斜线上&#xff0c;问有多少种摆法。 假设上图中红点为一个皇后的位置&#xff0c;那么他的同行&#xff0c;列&#xff0c;斜线上都不能再放置…

数据结构与算法-- 八皇后问题(多种实现方案)

八皇后问题解法一(排列筛选法) 本篇我们承接上一篇中的思想&#xff0c;想到了一个经典的算法题&#xff0c;八皇后问题&#xff1a;题目&#xff1a;在8*8的国际象棋上摆放8个皇后&#xff0c;使得其互相不能攻击&#xff0c;即任意两个换后不能在同一行&#xff0c;同一列&a…

C语言开方问题求助

求助&#xff1a; 使用的是Devcpp进行的编程尝试 在写程序的时候遇到了个问题&#xff0c;运行后结果显示为1#j 后来在朋友的帮助下改正了程序&#xff0c;解决了错误。之后的话&#xff0c;我按照我朋友的改正过的程序自己再重新打了一遍&#xff0c;结果运行后的结果还是显示…

C语言笔记

目录 基础... 3 基本类型数据... 5 定义变量... 6 进制... 6 ASCII&#xff08;阿斯克码&#xff09;... 7 输入输出... 8 printf&#xff08;&#xff09;将变量的内容输出到显示器上... 8 scanf &#xff08;&#xff09;[通过键盘将数据输入到变量中] 9 运算符... …

c语言 大数开方,大数加法之C语言函数法(只有正数版)

由于某些原因&#xff0c;我于今天2017-4-19将我的博文搬到博客园了&#xff0c;以后我就在这里扎根了。 之前想过在博客写文章方便日后复习&#xff0c;但一直未能实现&#xff0c;所以&#xff0c;现在这篇是我个人人生中第一篇博客&#xff0c;所以写博客完全没经验&#xf…

开平方的快速算法(C代码)

目录&#xff1a; 一、牛顿迭代法 二、采用移位、加减法、判断和循环实现开平方 三、效率远高于牛顿迭代法开平方法 1、原理 2、实现代码 四、卡马克快速开平方算法(推荐) 1、C-Free模拟验证卡马克开平方 2、移植到实际的项目 3、卡马克快速开平方的由来 1&#xff0…

windows 区域截屏以及延迟截屏

提起在Windows&#xff0c; 我们都会用到截屏功能&#xff0c;今天论述一下window 10系统自带的截图应用Snipping Tool 打开Snipping Tool 找到任务栏下的放大镜图标&#xff0c;点击 在下方输入snipping&#xff0c;会在左侧找到截图软件Snipping Tool&#xff0c;点击可进入…

小米手机解决此区域不可截屏

小米手机解决此区域不可截屏 无意中暂停视频弹出消息&#xff0c;想试试可不可以截屏竟然可以截屏&#xff0c;但是视频一播放就截屏不了了&#xff0c;录屏也是&#xff0c;直接变黑或者是直接提示弹窗&#xff0c;嘻嘻嘻嘻小米bug还是有好处滴

浏览器网页截屏实用小技巧

浏览器开发者工具中自带的截屏太方便了&#xff01; 打开开发者工具&#xff0c;输入 ctrl shift P 快捷键&#xff0c;输入screenshot&#xff0c;出现了四个选项&#xff0c;分别是&#xff1a; 1.area screenshot - 区域截图 2.full size screenshot - 对浏览器所有内容…

如何利用计算机截屏快捷键,电脑怎么截图 电脑选区域截图怎么截 电脑截图快捷键是什么...

电脑怎么截图 按照操作上从易到难的顺序&#xff0c;给你推荐五种截屏方式 &#xff1a; 第一种&#xff1a;Ctrl PrScrn 使用这个组合键截屏&#xff0c;获得的是整个屏幕的图片; 第二种&#xff1a;Alt PrScrn 这个组合键截屏&#xff0c;获得的结果是 当前窗口的图片; 第三…

iOS 截屏指定区域

转自&#xff1a;链接&#xff1a;https://www.jianshu.com/p/39db0fa66c0e 指定截屏代码实现 全屏截图效果 全屏截图效果 指定区域截屏效果 指定区域截屏效果 这里先上代码&#xff0c;代码后面有相关方法的解释第一种方法代码下载 /**创建一个基于位图的上下文&#xff0…