从八皇后问题思考回溯法

article/2025/9/10 16:34:36

一、八皇后问题

八皇后是经典的回溯法问题,题目是说将八个皇后,放到8×8的国际象棋棋盘中中,使得任意两个皇后都不能在同一行、同一列以及同一条对角线上。下图是一个四皇后的搜索示意图。
在这里插入图片描述

八皇后问题可以通过暴力法求解,代码也很短:

代码1

for(solu[1] = 1; solu[1] <= 8; solu[1]++)for(solu[2] = 1; solu[2] <= 8; solu[2]++)for(solu[3] = 1; solu[3] <= 8; solu[3]++)for(solu[4] = 1; solu[4] <= 8; solu[4]++)for(solu[5] = 1; solu[5] <= 8; solu[5]++)for(solu[6] = 1; solu[6] <= 8; solu[6]++)for(solu[7] = 1; solu[7] <= 8; solu[7]++)for(solu[8] = 1; solu[8] <= 8; solu[8]++)if(不冲突)  output();

代码很好理解,但是问题在于:
1)这种写法本身不可取,因为如果皇后很多的话,这里的循环重数会很多,甚至如果皇后个数是未知数的话,程序更是没法写。

2)这种写法,时间复杂度极高(如果最开始两个皇后如果都放在第一列,那么后面6个皇后如论如何摆放都无济于事。虽然回溯法复杂度依然很高,但是可以通过剪枝的方法省去类似很多不必要的搜索。

为了解决上述问题,我们提出回溯法,回溯法的核心思想是:
1)如果发现错误立即改正,比如上面说到的,我们这里不可能让两个皇后出现在同一列的事情发生,如果有,则重新选择位置。

2)如果某一个皇后在一行没有任何位置可以放下去(无论如何都会跟前面的皇后冲突),那么我们有理由认为是前面的皇后放的位置不合理,因此回退到上一个皇后重新放置,这既是回溯。

代码2

const int n = 8;
int solu[n+1];bool NoConfilict(int k){for(int i = 1; i < k; i++)if(solu[i] == solu[k] || (k-i == abs(solu[i]-solu[k])))return false;return true;
}void PlaceQueue(int k){ //放置第k个皇后,因为不能在同一行,因此皇后k放在第k行if(k == n+1) //如果已经到第n+1行,则得到了一个正确的解Print();else for(int i = 1; i <= n; i++){solu[k] = i;if(NoConfilict(k)) //当前皇后跟之前皇后不冲突,放下一皇后,如果这一行都放不下,回溯。PlaceQueue(k+1);}
}

二、全排列问题

有了八皇后问题的解,其实很容易修改成全排列的问题,如下所示1 2 3的全排列棋盘。我们依然可以想象n×n的一个棋盘,如果不考虑冲突的话,第i行表示第i个数可以是1-n之间的所有数,但是因为是全排列,所以i之前选定的数字,i及后续的数不能跟之前重复。
在这里插入图片描述
这里定义冲突的方式跟八皇后问题不太一样,可以看到这里的冲突就是之后的数字跟之前不一样即可,怎么不一样呢? 你很容易发现,只要不在同一列即可,相比之下,八皇后问题的冲突更为苛刻,因此我们只需要将八皇后问题的冲突判定方法的后半段删除即可。

代码3

bool NoConfilict(int k){for(int i = 1; i < k; i++)if(solu[i] == solu[k]) //注意这里的变化return false;return true;
}

然而判断在不在同一列只需要一个标记数组即可,因此一般我们有更简洁的写法:

代码4

const int n=3;
int solu[n+1], visit[n+1];void FillGrid(intk){if(k==n+1)Print();else for(inti=1;i<=n;i++){if(!visit[i]){solu[k]=i;visit[i]=1;FillGrid(k+1);visit[i]=0;}}
}

全排列的解法很多,比如字典序法、邻位交换等很多方法,读者可以参加组合数学。这里将另一种常见的递归全排列算法,代码很简短,但是却不是很好理解的一种写法,如下所示:

代码5

void solve(int k,int n){if(k==n+1)print(n);else for(int i=k;i<=n;i++){swap(a[k],a[i]);solve(k+1, n);swap(a[k],a[i]);}
}

我们注意到代码3和代码4中,我们每一行都会遍历n个位置,但实际上我们每一行并不是n个数都可以选择,那么我们是否可以每次给下一层限定一个区间呢?如果第1个数当然是n个数都可以选择,第2个数呢,加入第1个数选定为x后,那么第2位只能选取1~n之间除了x以外的其他数字,后续情况,以此类推。如下图所示:

第一个全排列:1 2 3 4 5 5 6 7 8
在这里插入图片描述

某一次全排列:3 4 5 6 8 7 1 2
注意每一行的交换情况,每一行的第一个与紫色框交换:
在这里插入图片描述

那么其实上述代码5就是这个思路,解读一下代码:

solve(k,n) :求解[k,n]的全排列
for(int i=k;i<=n;i++) :第k位的取值范围是[k,n]之间的所有数字
swap(a[k],a[i]) :第k位是需要轮流[k,n]之间的数字,所以依次将第k位和后续的位交换
solve(k+1,n): 第k位确定后,自然可以考虑k+1位
swap(a[k],a[i]) :我们注意到,后面还有一个交换,这一个交换是为了让之前交换的数字还原,使得下一次交换不受影响。

每一次得到一个[k,n]的排列,实际上包含了从第k位到第n位的n-k+1次交换,但是每次回溯的过程中,之前的交换全部换回来,保证了再次回溯到k的时候,[k,n]之间的所有数字跟最开始的序列完全一致,这也使得下一次我用第k位跟第i+1位交换的时候,a[i+1]能正确的放到a[k]的位置,同时a[k]放置于a[i+1]的位置。

三、n个元素取m个元素的组合

理解了八皇后问题后,其实很多问题都可以求解。比如Leetcode77就可以通过八皇后问题的思路求解。这道题目要求1~n的n个元素中,求包含m个元素的所有子集,要求每一个子集的元素递增排列。

这里我们也想想一个棋盘,第一个元素就是第一个皇后,他可以取的数位1~n-m+1, 第二呢?2~n-m+2,依次类推直到取完m个数为止。需要注意的是,第i个元素的取值应当从第i-1个元素的下一个位置开始取值。 每当一行取完之后,皇后走投无路,OK,回溯到上一行。


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

相关文章

八皇后问题(Python)

一.问题简介 八皇后问题&#xff1a; 如何能在 8*8 的国际象棋棋盘上放置八个皇后&#xff0c;使得任何一个皇后都无法直接吃掉其他的皇后&#xff1f;为了到达此目的&#xff0c;任两个皇后都不能处于同一条横行、纵行或斜线上。 二.几种思路和方法 1.回溯法递归思想 如图所…

八皇后问题详解(四种解法)

所有源码都在github上(https://github.com/seasonyao/eight_queen_question) 如果你去百度百科八皇后这个问题,你会发现人家也是历史上有头有脸的一个问题,最后一句“计算机发明后就有一万种方式解决这个问题”读起来也让程序猿们很快活。闲话少说,开始阐述我的思路: 最…

八皇后问题

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

八皇后问题(适合初学者的写法)C语言

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

八皇后问题,秒懂递归回溯(有图详解|c语言)

目录 &#x1f478;&#x1f3fb;前言 &#x1f478;&#x1f3fb;题目介绍 &#x1f478;&#x1f3fb;引入&#xff1a; &#x1f478;&#x1f3fb;解决思路&#xff1a; &#x1f478;&#x1f3fb;理论存在&#xff0c;实践开始&#xff01; &#x1f478;&#x1f…

利用ngrok实现域名映射局域网ip

前言 相信很多开发者都有这样的需求&#xff0c;需要让外网访问你本地的服务器&#xff0c;方便调试本地代码&#xff0c;或者让别人体验到自己做的应用。那么这时&#xff0c;我们需要做的就是将我们本地的端口映射到一个外网的端口上&#xff0c;也就是内网穿透。常见的解决…

python调用手机摄像头,实现实时调用摄像头,需要你的电脑和手机在同一个局域网内

1、android手机上安装一款APP&#xff1a;IP摄像头&#xff0c;app的图片如上图 2.调用代码如下 import cv2cv2.namedWindow("camera", 1) # 开启ip摄像头 video "http://admin:admin10.0.0.32:8081/" # 此处后的ipv4 地址需要改为app提供的地址 cap c…

02、处于不同局域网下的Socket通信(网络部分理论知识)

目录 一、服务器 1、服务器的种类和功能 2、服务器的操作系统 3、IIs、Apache、Tomcat 4、云服务器 弹性云服务器&#xff08;Elastic Cloud Server&#xff0c;ECS&#xff09; 云服务器安全组 二、OSI七层模型与TCP/IP五层模型 三、外网、内网、公网、私网 内网穿透…

使用wireshark抓取聊天信息(局域网内的udp通信)

文章目录 1&#xff0c;实验目的2&#xff0c;实验操作3&#xff0c;总结4&#xff0c;附件 1&#xff0c;实验目的 1.分析这程序所采用的是udp还是tcp 2.在抓取包中找到窃取到的聊天信息 (英文字符和汉字可能经过了某种编码转换&#xff0c;数据包中不是明文) 3.如果是网络连…

安装黑群晖找不到局域网电脑_黑群晖洗白太复杂?我用蒲公英P5轻松实现

前言: 随着网盘时代的结束,剩下的网盘供应商又开启了垄断方式,所以越来越多的小伙伴开始自己组自己的家庭NAS网络存储服务器。比如笔者的一个好基友就是如此。其实开始笔者是想让他直接一步到位,买群晖或者铁威马的NAS,在放入硬盘就可“一劳永逸”。然而,这个小伙伴看到了…

内网穿透实现局域网内搭建私服务器

使用云服务器实现内网穿透。内网里建立一台老旧win机专门用来挂pt&#xff0c;在上面存储视频和软件&#xff0c;而后映射在外网中&#xff0c;通过手机和电脑随时随地的下载和在线观看win机上的视频和文件。 1、修改ssh的默认端口 在公网中使用常用软件的默认端口会导致自己的…

局域网终结者_p2p终结者怎么安装使用 p2p终结者安装使用方法【介绍】

p2p终结者是一款局域网控制软件&#xff0c;他的主要功能就是控制和限制同一个局域网内其它的上网用户&#xff0c;如限制不让别人上QQ&#xff0c;不让别人开网页和不让别人下载&#xff0c;只要他和你在同一网之内你就可以控制他&#xff0c;并且神奇的是&#xff0c;不需要动…

Kali Linux-MSF远控局域网手机

前言 严正声明&#xff1a;本文仅限于技术讨论与分享&#xff0c;严禁用于非法途径。 本文目的&#xff1a;演示如何借助Kali Linux系统的Metasploit渗透测试框架生成远程控制程序&#xff0c;然后感染局域网内的Android手机&#xff0c;从而实现对目标手机数据的读取、音频的…

超级眼局域网监控软件 员工禁止软件 可以控制时间段

第一步&#xff1a; 下载超级眼局域网监控软件&#xff1a; 将经理端安装在管理者的电脑上&#xff0c;员工端安装在需要被监控者的电脑上。 第二步&#xff1a;在经理端电脑上操作。打开管理端软件&#xff0c;扫描所有的被控电脑。然后选择需要管理的电脑&#xff08;可以全选…

Kali使用Netdiscover探测局域网中存活主机

1、netdiscover介绍 Netdiscover 是一个主动/被动的ARP 侦查工具。使用Netdiscover工具可以在网络上扫描IP地址,检查在线主机或搜索为它们发送的ARP请求。 2、 主动模式:主动模式顾名思义就是主动的探测发现网络内主机,但是这种方式往往会引起网络管理员的注意。 打开Kali终…

如何避免计算机被别人共享,win7如何防止别人偷窥电脑 win7防止别人偷窥电脑操作方法...

我们都知道在win7系统中&#xff0c;可以设定开机密码或者屏保密码来防止我们的电脑被别人使用&#xff0c;不仅win7系统可以设置开机密码或者屏保密码&#xff0c;其他版本的系统也是可以设置的&#xff0c;那么win7如何防止别人偷窥电脑呢?下面为大家介绍win7防止别人偷窥电…

【时间之外】监控你的电脑只需8步

最近某安全厂商很火&#xff0c;很多离职员工都是被这套系统抓出来的。其实原理很简单&#xff0c;本文就用很多人都用过的kali系统&#xff0c;告诉你&#xff0c;想要控制你的电脑有多简单&#xff01; 网上的文章很多&#xff0c;如这篇&#xff0c;Kali攻防&#xff0c;写…

详细介绍别人电脑访问到自己电脑运行的项目

文章目录 让别人远程访问你的代码网站项目或临时演示你的项目给客户的方式详解 引言一、创建一个你想要别人访问的项目二、明确你想要将这个网站或者项目存放的地方 终端分类服务器设备WEB服务器三、部署我们的网页 本地部署流程进入浏览器输入网址访问获取本机的IP地址&#…

监控手机屏幕、监控电脑屏幕方案

一&#xff1a;手机投屏 实时监控多个手机屏幕&#xff08;<3台&#xff09; ApowerMirror软件&#xff0c;终生179&#xff0c;可同时连接3部手机 网络环境&#xff1a;电脑与测试手机需要在同一个WiFi网络环境下。(要求手机型号不同) 软硬件环境&#xff1a;电脑和手机分别…

基于VC++的局域网内主机监控系统设计与实现

局域网内主机监控系统 目录 引言 2 1.1 编写目的 2 1.2 项目背景 2 1.3 课题内容和要求 3 1.4 名词解释 4 参考文献 4需求分析 5 2.1 现有系统概述 5 2.2 对新系统的要求 5 2.3 系统要求 6 2.4 对功能的规定 6 2.5 对性能的规定 6 2.6 运行环境规定 7 2.6.2 软件配置 7系统架…