【回溯法】n皇后问题并输出每种解的情况 C语言版

2023-10-30

问题描述:

 

在n×n的方格棋盘上,放置n个皇后,要求n个皇后两两不在一行,不在一列,不在同一对角线上

 PS:

行不用检测,因为皇后本身就是一行一行往下放的,并且一行只能放一个,所以当放好一个皇后后,只需检测列及对角线的位置有无皇后  ,如下图这些位置

 

思路 【回溯法】

1.   从棋盘的第一行开始,依次遍历所有位置,依次判断当前位置是否能够放置皇后,判断的依据为:同该行之前的所有行中皇后的所在位置进行比较,是否在同一列,或者在同一条斜线上(斜线有两条,为正方形的两个对角线)。


2.   如果该行所有位置都不符合要求,则回溯到上一行,改变皇后的位置,继续试探。直到在当前行找到下一个合法位置。


3.   如果试探到最后一行,所有皇后摆放完毕,且找到了放置皇后的合法位置,那么解的个数加一,并再次回溯。最后一定要记得将棋盘恢复原样,避免影响下一次摆放。 

画一个更大的图方便我们找规律(以8皇后为例)

假设我在蓝色圆圈的这一行放皇后,那么就要检测这一列以及它的斜上斜下对角线,写出每个方格坐标我们可以发现,左上对角线坐标和相等,左下对角线差相等 

 假设我将皇后放在蓝色位置,那么我只需要查看蓝色这一行之前的所有行有没有放过(因为是一行一行放的,蓝色之后的行肯定没有)

对于n*n的棋盘,从第一行第一列开始放置皇后,然后在第二行,从左至右,找到第一个可以放置皇后的位置并放置一个皇后。那么什么时候会遇到一点问题呢?一种情况是,我在某一行找不到放置皇后的合法位置了;另一种情况是,每一行都放置了一个皇后,此时已经构成了一个解,需要寻找下一个解。对于第一种情况,我们需要把当前行的上一行的皇后移除,在代码上的表现,就是把a[i]的位置设置为上一行的皇后位置并从这个位置继续向右,找到第一个可以放置皇后的位置,并放置之;对于第二种情况,其实前半部分处理与第一种情况相同,但是不要忘记在返回的count加上一(因为此时已经有了一个解)
 

补充 

回溯法,又被称为“试探法”。解决问题时,每进行一步,都是抱着试试看的态度,如果发现当前选择并不是最好的,那么就回退一步重新选择。这种走不通就回退再走的方法就是回溯法。 

回溯和递归其实并不是一回事,它们之间唯一的联系就是,回溯法可以用递归思想实现。

代码 

#include <stdio.h>
const int N=10;  //最多的皇后个数 
int a[N];//a[i]表示第i行上的皇后放于a[i]列上,如a[3]=7表示第3行的皇后放在第7列上 
int count,n;  //存放解的个数 

//测试在(x,y)位置能不能放皇后 
bool check(int x,int y){  
	for(int i=1;i<=x;i++){
		if(a[i]==y) return false;  //判断是否同列(false,第i列已经放过) 
		if(i+a[i]==x+y) return false;  //斜上对角线(右对角线)已经放过 
		if(i-a[i]==x-y) return false;  //斜下对角线(左对角线)已经放过 
	} 
	return true; //以上三种情况都没有,说明该位置可以放皇后 
}
//输出解的情况 
Print(int n){
	count++;    //先记得个数+1 
	printf("第%d种解",count);
	for(int i=1;i<=n;i++){
		printf("(%d,%d)",i,a[i]);
	} 
	printf("\n");
}

//从放第row行开始求解n皇后的解 
void dfs(int row){
	if(row>n) {  //row>n 也可以写成row==n+1 
		Print(n);  // 表示超过了n行到达了边界,说明产生了一组解 ,直接输出
		return ;
	}
	for(int i=1;i<=n;i++){
		if (check(row,i)){   //检查是否冲突 
			a[row]=i;  //不冲突,将皇后放在i列上 
			dfs(row+1);  //进入下一行(递归调用后面的皇后) 
			a[row]=0;  //递归完毕后,还原第row行避免重复,所以进入下一行时吧刚才的row变为0,因为有多组解【回溯】 
		}
	}
} 
int main(){
	printf("输入n*n的棋盘数:"); 
	scanf("%d",&n);
	dfs(1);  //因为从第一行开始
	printf("一共有%d种解",count);
	return 0; 
} 

 测试结果

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【回溯法】n皇后问题并输出每种解的情况 C语言版 的相关文章

随机推荐

  • 请教Ado.Net按文本读取CSV/Txt文件时,如何禁止将内容转换成数字

    例如现有文件内容如下 文件内容开始 Column1 Column200001234 00005678 文件内容结束 读得的结果是 lt 1234 5678 gt 即它 智能 地认为我里面的内容为数字 而我希望它把内容当文本来处理 期望的结果
  • 重构总结

    之前就听说 重构 改善既有代码的设计 这本书很经典 一直没有机会拜读 书中讲的都是很实用的重构小技术 很多人肯定都用过 看完之后还需要在工作中多多使用 下面总结了一下这本书的知识点 方便日后查看
  • linux进程间信号量通信IPC(sem)

    一 信号量 信号量是一种用于提供不同进程间或一个从给定进程的不同线程间同步手段的原语 1 1 Posix信号量的选择 1 单个进程的各个线程共享 可以使用基于内存的信号量 2 彼此无亲缘关系的不同进程需使用信号量时 通常使用有名信号量 1
  • STM32无线网络监控传感器数据

    介绍 在此项目中 我们将首先创建一个无线传感器节点 传感器节点由四个基本组件组成 例如传感单元 处理单元 收发器单元和电源单元 传感单元可以由任何传感器组成 我正在使用BME280气压传感器 处理单元是STM32F103C微控制器 收发器单
  • Python之格式化字符串小练

    格式化字符串 a 3 b 5 print str a str b str a b 对于字符串的拼接显示 称为格式化字符串 有两种方案 的方式 print s s s a b a b s表示字符串 d表示整数类型 f表示浮点型的整数 info
  • python列表的三种遍历方法(for循环,索引,下标)

    列表是python中使用频率非常高的数据类型 用方括号 定义 接下来介绍遍历列表常用的三种方法 1 直接遍历 list1 1 24 34 44 533 5 219 for item in list1 直接遍历 print item 2 按索
  • Linux内核之ICMPv6详解

    要知道什么是ICMPv6协议 我们首先要知道什么是ICMP ICMP是一种面向无连接的协议 负责传递可能需要注意的差错和控制报文 差错指示通信网络是否存在错误 如目的主机无法到达 IP路由器无法正常传输数据包等 注意 路由器缓冲区溢出导致的
  • 执行git status命令时出现了“fatal: detected dubious ownership in repository“

    这个错误提示表示发现了版本库中存在可疑的所有权问题 即指定的目录 E take Class Rust MyRust 的所有者与当前用户不匹配 为了解决这个问题 Git提供了一个添加目录异常规则的方法 你可以按照下面的步骤进行操作 1 打开命
  • 前端基础知识之SVG&Canvas之间的区别与简单应用

    tip canvas 常用API fillRect x y width height 实心矩形 strokeRect x y width height 空心矩形 fillText Hello world 200 200 实心文字 strok
  • 8. R语言绘图系统介绍、高级绘图与低级绘图、【绘图参数】、绘图函数包

    b站课程视频链接 https www bilibili com video BV19x411X7C6 p 1 腾讯课堂 最新 但是要花钱 我花99 元买了 感觉讲的没问题 就是知识点结构有点乱 有点废话 https ke qq com co
  • HTML 个人简历源码

  • 使用HAL库开发STM32:系统时间基础及进阶使用

    文章目录 目的 基础使用 进阶使用 总结 目的 HAL库默认提供了系统时间 系统时间默认情况下由SysTick定时器计数产生 系统时间一方面用于HAL库自身调用 另一方面用户也可以使用 为开发带来便利 本文提到的相关使用主要应用于未使用OS
  • 5G赋能智慧城市白皮书 附下载地址

    随着经济社会的快速发展和加速转型 传统城市管理模式的局限性日益显现 随着全球城市化 进程的加快 为了应对人口 资源 环境等对城市发展的挑战 全球各国都以 智慧城市 建 设作为全新的城市发展理念和实践路径 而传统智慧城市建设中 由于细分智慧应
  • 应用层——电子邮件(SMTP、POP3、IMAP)

    目录 1 电子邮件系统及组成结构 1 1 电子邮件 1 2 电子邮件系统的组件 2 SMTP 邮件发送协议 2 1 SMTP的特征 2 2 SMTP的基本操作 2 3 SMTP协议的基本流程 2 4 SMTP交互与应答 2 5 SMTP与H
  • 预测性维护

    1 预测性维护 1 1 介绍 预见性维护 PdM 承诺在工厂车间达到前所未有的效率和安全水平 目前已建立的系统和流程的最佳实践 机器停机是生产线上最大的挑战之一 目前的MRO 维护 维修 操作 方法远未达到最佳生产水平 通过预测性维护 一旦
  • kettle对接hive

    kettle没有自带hive的驱动 如果在界面上直接选Hadoop Hive 2 3会报找不到驱动的错误 按照网上的解决方案修改了plugins文件夹里的配置文件后仍然无法解决 还是需要把驱动jar放入kettle里才可以 docker c
  • C++:多线程的正确打开姿势

    目的 本例简介c 11中thread库如何创建与停止线程 实现 如下的实例中 通过ThreadWrapper start 方法启动线程 通过ThreadWrapper stop 方法停止线程 线程的主体函数为Thread run 方法 in
  • Servlet 基础知识及操作

    一 什么是servlet Servlet Server Applet 是Java Servlet的简称 称为小服务程序或服务连接器 用Java编写的服务器端程序 具有独立于平台和协议的特性 主要功能在于交互式地浏览和生成数据 生成动态Web
  • [POI2008]CLO-Toll

    题目链接 本题有个小点需要注意 如果说它是多个相互不连通的图 也有可能形成一个可行解 多个环嘛 然后剩下的 就是dfs去跑 如果跑出了返祖边 那么这个返祖边抵达的点 将改变原来的方向 剩下的就都是正方向 dfs直接跑就是了 include
  • 【回溯法】n皇后问题并输出每种解的情况 C语言版

    问题描述 在n n的方格棋盘上 放置n个皇后 要求 个皇后两两不在一行 不在一列 不在同一对角线上 PS 行不用检测 因为皇后本身就是一行一行往下放的 并且一行只能放一个 所以当放好一个皇后后 只需检测列及对角线的位置有无皇后 如下图这些位