八皇后问题详解(深度优先搜索)C++

八皇后问题详解(dfs深度优先搜索)C++

八皇后问题概念

八皇后问题是由国际象棋棋手马克斯·贝瑟尔于1848年提出的问题。
在这里插入图片描述

问题表述为:在8×8格的国际象棋上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一或同一斜线上,问有多少种摆法?

思路讲解

条件:每一行、每一列、主副对角线上只能有一个皇后。 而且一定是有解的。
思路不难。肯定的是,最终每行只有一个皇后,那么可以以行数为大基准逐行搜索,对第n行0搜索时,依次对每一列进行搜索,一旦找到满足条件的位置,就跳到下一行继续搜索,如果一行中的8列都不能满足条件就返回上一行,继续搜索,直到找到满足条件的一条路径(一种摆法)。然后跳出这条路径,到第一行下一个符合的元素继续搜索。
极速脆皮猫

代码步骤讲解

1

#include<bits/stdc++.h>
using namespace std;
int ans=0;//总摆法数 
bool col[10],v1[20],v2[20];//标记该列、主对角线、右对角线,均无其他皇后为false(全局布尔变量初始为false)

这里用ans记录摆法的总数(题目要求的答案)。然后定义三个布尔数组,col记录列是否满足条件,v1记录主对角线是否满足条件,v2记录副对角线是否满足条件,如果满足(即可以放皇后)为false,不满足为true。
1.定义全局变量是因为这些变量的生存期一直到程序结束,并且一直不需要初始化,因此变量不会因为出了函数作用域而改变(避免了一些指针的操作)。使程序更简洁。
 2. 列是8,于是定义10个元素的数组;(算上顶点)主副对角线各有17个,于是两个数组定义元素20个。

2

int main(){
    dfs(0);//从第0行开始找 
    cout<<ans<<endl;
    return 0;
}

先把主函数写好,这样更能看清深搜函数(dfs)的作用。这题没有输入,直接从第0行开始深度搜索(后面详细会讲),dfs内会计算ans(摆法总数),最后在主函数中输出。

3

void dfs(int r){
	//如果超出最大行数,则该路径结束,继续找下一个路径 
	if(r==8){
		ans++;//总方法数+1 
		return;
	}

if这里是递归终止的条件。参数r代表行数。进入dfs后首先判断行数有没有超过8(由于存放在数组中,0代表1,7代表8),如果已经到了第九行,说明前8行已经搜索完了,找到了一种摆法(否则第八行找不到的话,就会返回第7行,因而到不了第9行)。所以结束当前路径dfs,进入除去已找到摆法中第一行的元素的下一列。

4

for(int i=0;i<8;i++){
		//如果此位置所在列、主对角线、右对角线均无其他皇后,则放置一个皇后 
		if(!col[i]&&!v1[r+i]&&!v2[r-i+8]){
			col[i]=v1[r+i]=v2[r-i+8]=true;//先标记为true,即此位置所在列、主副对角线已不能放其他皇后 
			dfs(r+1);// 接着去下一行搜索符合放置皇后条件的位置 
			col[i]=v1[r+i]=v2[r-i+8]=false;//如果路径行不通,返回上一级,标记为true,相当于该位置未走过 
		}
	}
}

这里开始深搜,从当前行r开始往后找每一列,一旦找到符合条件的位置就放一个皇后(标记为true)。然后dfs(r+1)进入下一行继续每行找。最后一句是如果在这一行搜索不到符合条件的位置就返回上一行并把上一行此路径中标记为true的元素改为false(此时上一行该位置可以放皇后但如果放了,在这一行是搜索不到符合条件的位置,所以上一行该位置不能放),接着继续在上一行原位置的下一列进行搜索。

数组下标:这里i表示第i行。对于对角线的表示,因为我们是从左上角开始搜索的(或者把棋盘看成一个二维数组,起始点自左上角),那么如果将棋盘类比成平面直角坐标系,左上角的点就是坐标原点O。可以把i看作横坐标,r看作纵坐标,若主对角线v1是不通过O的,那么v1上的点的横纵坐标之和不变,即r+i不变,副对角线v2上的点的横纵坐标只差不变即r-i不变,但是r-i会小于0(最小为0-8==-8),由于数组下标的限制,所以要对r-i加8。(如下图)
极速脆皮猫

完整代码

#include<bits/stdc++.h>
using namespace std;
int ans=0;//总方法数 
bool col[10],v1[20],v2[20];//默认都是false(该列、主对角线、右对角线均无其他皇后) 
void dfs(int r){
	//如果超出最大行数,则该路径结束,继续找下一个路径 
	if(r==8){
		ans++;//总方法数+1 
		return;
	}
	for(int i=0;i<8;i++){
		//如果此位置所在列、主对角线、右对角线均无其他皇后,则放置一个皇后 
		if(!col[i]&&!v1[r+i]&&!v2[r-i+8]){
			col[i]=v1[r+i]=v2[r-i+8]=true;//先标记为true,即此位置所在列、主副对角线已不能放其他皇后 
			dfs(r+1);// 接着去下一行搜索符合放置皇后条件的位置 
			col[i]=v1[r+i]=v2[r-i+8]=false;//如果路径行不通,返回上一级,标记为true,相当于该位置未走过 
		}
	}
}
int main(){
    dfs(0);//从第0行开始找 
    cout<<"总共有"<<ans<<"种摆法"<<endl;
    return 0;
}

在这里插入图片描述

解决!
本人拙见,请读者多加指教。

  • 28
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
洛谷八皇后问题是一个经典的回溯算法问题。根据引用中的描述,要求将8个皇后放置在8*8棋盘上,使得它们彼此不受攻击,即任何两个皇后都不在同一行、同一列或同一斜线上。 引用[2]给出了一个c++代码的实现。这段代码使用了回溯法来解决八皇后问题。通过递归地尝试每一行中的每一列,找到合适的位置来放置皇后。 具体的过程如下: 1. 定义一个一维数组x,用来存储每行皇后的位置。 2. 从第一行开始递归,尝试每一列的位置。 3. 对于每个位置,检查是否与之前的皇后位置冲突,即是否在同一列或同一对角线上。如果冲突,就继续尝试下一列;如果不冲突,就将该位置存入数组x,并继续递归下一行。 4. 当递归到最后一行时,打印出当前的皇后位置,并将可行解的数量加一。 5. 回溯到上一行,尝试下一个列的位置。 6. 当所有的解都找到后,输出解的数量。 根据引用给出的代码,共有92种不同的放置方式,即解的数量为92。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [8皇后_八皇后问题c++实现_](https://download.csdn.net/download/weixin_42665725/26278676)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [八皇后问题C++递归回溯法(注解)](https://blog.csdn.net/qq_43656233/article/details/105571396)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

极速脆皮猫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值