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

这篇具有很好参考价值的文章主要介绍了八皇后问题,秒懂递归回溯(有图详解|c语言)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

👸🏻前言

👸🏻题目介绍

👸🏻引入:

👸🏻解决思路:

👸🏻理论存在,实践开始!

👸🏻难点1:如何表示对角线被占领?

👸🏻难点2:如何用递归的方法来放皇后?

👸🏻难点3:如何实现回溯?

👸🏻难点4:如何实现皇后位置的输出?

👸🏻全部代码如下:

👸🏻总结: 

Love is worth years.❤热爱可抵岁月漫长。


前言

各位和我一样的刚学完递归的小白们,是不是突然遇见了一个大BOSS,八皇后👸🏻问题!!把自信的说着“老子递归学好了!”的你一棒子打回了出生点,就像你刚玩只狼遇到的那个大胖子,刚玩原神遇到的雪山。今天,我就和大家一起学习一下这个著名的八皇后👸🏻问题。

八皇后问题c语言,c语言,c语言,算法,学习


题目介绍

八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法并输出每一种摆法。

八皇后问题c语言,c语言,c语言,算法,学习

 升华:我在做这个东西的时候本来想用人脑将他们摆进去,发现太!麻!烦!可能这就是计算机存在的意义吧!


引入:

不知道大家有没有在前面学习递推的时候学过马拦过河卒的问题没看过的可以点这,这个问题和那个问题都是一个棋类的问题,他们也有相同之处,都是需要用一个数组来表示这个地方有没有被占领,象棋的那个题是马占领的地方需要标记,而这个题是皇后占领的每一行每一列每一个对角线都需要标记。所以我们可以采用一些个数组来表示这个地方被皇后占领了当然这个题还用到了一个重要的算法就是递归算法和回溯的思想


解决思路:

1.首先定义三个数组分别表示列被占领,左对角线被占领,和右对角线被占领。因为我们一行一行的放进去所以不用考虑行的问题。👸🏻

2.利用递归算法在没有被占领的地方一行一行的放入我们的皇后。👸🏻

3.利用递归和回溯算法一行一行的放入皇后。👸🏻


理论存在,实践开始!

难点1:如何表示对角线被占领?

用数组来表示列被占领很简单,只要让皇后所在的那一列的数组的值都等于0,就可以解决这个问题,但如何用数组来表达对角线呢??你知道吧!你数一数,这一共有多少个对角线?一共有15条对角线,所以我们可以定义两个数组d1和d2来用来表示两个方向的对角线。如果被占领就是0没有被占领就是1

定义代码如下:

int d1[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//定义上对角线
int d2[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ;//定义下对角线

如何在摆放的时候来确定哪一行哪一列呢?这样定义十五行太好定义了但是想要表示就难了,我们来研究一下这个东西。看下图,如这个第五列第三行的这个女皇,这个皇后占领了这两个对角线, 如何来表示上对角线(皇后👸🏻的左上和右下从右上脚开始1、2、3、4、5...)?d1[n-col+7]=0;(col为女皇所在的列)也就是让行减去列再加上7就是表示的上对角线的个数。八皇后问题c语言,c语言,c语言,算法,学习

有小朋友要问了:你咋知道的???给你看一个上对角线的图!!

用行-列得到的图是这样的(我的那个棋盘没有第零行,大家可以看成有第零行的和列的,这个图太难改了你懂我的意思吧):

八皇后问题c语言,c语言,c语言,算法,学习

 而把这个数加7也就是行-列+7,是这样的:八皇后问题c语言,c语言,c语言,算法,学习

 这样我们不就可以用行标和列标来表示他所在的上对角线了嘛,神器吧!!

希望各位xdm都把这个背过说实话我要是自己推我也推不出来这个玩意!!

下对角线:用行加列就会神奇的发现变成了下面这个样子:八皇后问题c语言,c语言,c语言,算法,学习


好了xdm现在让我们大声背三遍:

上对角线:行-列+7!!行-列+7!!行-列+7!!

下对角线:行+列!!行+列!!行+列!!


好了记住了吧!!!不要忘记了!像对待女朋友的生日一样对待这几个字!!!

这样我们就可以用:d1[n-col+7],d2[n+col]来读取皇后的对角线的占领情况了!

这个难点解决了,我们来进入下一个难点递归。


难点2:如何用递归的方法来放皇后?

1.皇后的放置问题:place[8]={0};来表示皇后的位置的话,用table[8][8]={0};来表示一个8*8的大棋盘用一个for循环来访问棋盘的每一行,如果这个位置可以放(那几个约束条件都是1没有被占领的话)我们就可以让这一行的皇后的位置棋盘上放上皇后即place[n]=col;,表示皇后在此列👸🏻(一会打印的时候可以用的到)然后让皇后的列和那两个对角线为0,表示占领! flag[col]=0; d1[n-col+7]=0;d2[n+col]=0;

2.皇后的递归调用问题:

我们想要一行一行的摆放皇后,然后一列一列的尝试对不对

用col来表示列的话,用一个循环:    for (col=0;col<8;col++)来访问每一列!

放置皇后用数组place[n]=col;(n表示行)来表示这个列,我皇后👸🏻占了!!!

flag[col]=0;  d1[n-col+7]=0;d2[n+col]=0;//将该皇后所在的行、列、对角线设置为被占领

这样我们皇后在一行的放置问题解决了!,那么如何访问每一行呢?

这时候我们就需要用到神奇的递归神器!

如果queen(n+1);发现,老资👸🏻没座位了!他就会对queen(n);说:“姐姐,姐姐你能不能去下一个座位让妹妹我坐下呀”如果queen(n);发现她如果向下面去她也没座位了她会向queen(n-1)说:....直到这8个皇后全坐下了,他们不吵架了,我们才能把这个棋盘输出出来!!!

这不就是老和尚给小和尚讲故事的递归嘛,而这个故事的大结局是皇后全都坐下!

我们如果这个行数小于七行(初始行为0你要是初始行为一可以加一)我们就可以继续向下摆放,对不对,就继续使用递归,来摆这个棋盘的下一行

if(n<7)    {queen(n+1);}//当行数小于7时;递归调用下一行。

如果我们的皇后把这次棋盘的摆好了我们就可以把这个棋盘输出出来了!

else{print();}(这个函数我们下面讲)//调用输出函数,

请大家看代码:

int queen(int n )//定义递归回溯函数
{
	int col;
	for (col=0;col<8;col++)
	{
		if (flag[col]&&d1[n-col+7]&&d2[n+col])//判断皇后是否冲突
		{
			place[n]=col;//放置皇后
			flag[col]=0;
			d1[n-col+7]=0;
            d2[n+col]=0;//将该皇后所在的行、列、对角线设置为被占领
			if(n<7)	{queen(n+1);}//当行数小于7时;递归调用下一行
		else{print();}//调用输出函数
			flag[col]=1;//回溯
			d1[n-col+7]=1;
			d2[n+col]=1;
		}
	}
	return count;
}

输出了一个棋盘还不够,我们要输出所有的棋盘,怎么办呢??这时候我们就要请我们的回溯算法登场了! 


难点3:如何实现回溯?

因为我们用的是递归算法如果这一行输出不了我们就把责任退回给上一行,直到我们找到了一个棋盘上面正好能够放着这八个皇后的时候我们就把他打印出来了。逻辑是不是这样的

那么如果我们在循环的最后加上flag[col]=1; d1[n-col+7]=1; d2[n+col]=1;是不是就是把这个占领的皇后踢出去了,然后再把这个皇后放在下一列来看看后面的那些皇后能不能成功摆放?

什么时候会触发这个回溯算法呢??

答案是:当上面的递归算法全执行完了一次,并且输出了一个棋盘后,我们就可以让她执行第二次了!!

我们来继续讲一个故事:最后那个👸🏻在自己家里呆够了,老娘不想呆了,她又和楼上说,我要去下一个地方玩玩,你们看看怎么给我协调一下,原来我的位置就空出来了。楼上想;你去下面我去哪啊!于是他只好和楼上说,楼下和他说过的话。

这就是flag[col]=1; d1[n-col+7]=1; d2[n+col]=1;老娘不想待了,全给我搬家!

运行完这个以后呢,for循环中的col就进入下一列了,他这样一进不要紧,又触发了递归算法,一层一层的倒换,来满足需求。

当这个皇后全尝试了一遍其他能尝试的地方,就安稳了。

这样讲应该能讲明白为什么使用这个回溯算法,以及回溯算法为什么在if里面了吧如果不在if里面,这个回溯算法就没有意义了。

            flag[col]=1;//回溯
			d1[n-col+7]=1;
			d2[n+col]=1;

难点4:如何实现皇后位置的输出?

这个时候我们可以直接用一个输出函数来输出

这部分简单直接上代码:

void print()//定义输出函数
{
	int i,j;
    count++;//每调用一次输出函数number自加一次,记录摆放方法个数
	printf("No.%2d\n",count);
	int table[8][8]={0};//设置一个8*8的棋盘
	for (i=0;i<8;i++)
	{
		table[i][place[i]]=1;//将每一行皇后所在位置赋值为1
	}
	for (i=0;i<8;i++)
	{
		for (j=0;j<8;j++)
		{
	printf("%d|",table[i][j]);
		}printf("\n");
	}
}

这样我们就能输出这些傲娇的皇后们了!!


全部代码如下:

#include<stdio.h>
int place[8]={0};//皇后位置
int flag[8]={1,1,1,1,1,1,1,1};//定义列
int d1[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//定义上对角线(共有15个对角线,
//因此定义一个长度为15的数组,初值为1代表该对角线没有被皇后占领,
//若被皇后占领则赋值为0
int d2[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ;//定义下对角线
int count=0;//记录输出次数
void print()//定义输出函数
{
	int i,j;
    count++;//每调用一次输出函数number自加一次,记录摆放方法个数
	printf("No.%2d\n",count);
	int table[8][8]={0};//设置一个8*8的棋盘
	for (i=0;i<8;i++)
	{
		table[i][place[i]]=1;//将每一行皇后所在位置赋值为1
	}
	for (i=0;i<8;i++)
	{
		for (j=0;j<8;j++)
		{
	printf("%d|",table[i][j]);
		}printf("\n");
	}
}
int queen(int n)//定义递归回溯函数
{
	int col;
	for (col=0;col<8;col++)
	{
		if (flag[col]&&d1[n-col+7]&&d2[n+col])//判断皇后是否冲突
		{
			place[n]=col;//放置皇后
			flag[col]=0;
			d1[n-col+7]=0;
            d2[n+col]=0;//将该皇后所在的行、列、对角线设置为被占领
			if(n<7)	{queen(n+1);}//当行数小于7时;递归调用下一行
            else{print();}//调用输出函数
            flag[col]=1;//回溯
			d1[n-col+7]=1;
			d2[n+col]=1;
		}
	}
	return count;
}
int main()
{
count=queen(0);//从第0行开始摆放皇后
printf("共有%d种方法",count);//输出摆放皇后的方法个数
	return 0;}

运行结果部分如下:

八皇后问题c语言,c语言,c语言,算法,学习

可以看到一共有92种方法。


总结: 

递归问题就是推责任问题,下边不行就推给上边,上边不行,就推给上上边。

而回溯就像一个追求完美主义的人,我这边成了,我还要试试另一种解法行不行,等我把所有的结果都试出来就完美了!

我们人呢,既不能追求完美,也不能推卸责任,只有做好自己。

大家仔细的把这个八皇后算法搞懂,就会发现原来递归和回溯这么简单,不要得过且过!!

八皇后问题c语言,c语言,c语言,算法,学习文章来源地址https://www.toymoban.com/news/detail-782343.html

Love is worth years.❤ 热爱可抵岁月漫长。

到了这里,关于八皇后问题,秒懂递归回溯(有图详解|c语言)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 算法:回溯算法(以解决n皇后问题为例)

    算法:回溯算法(以解决n皇后问题为例)

    基本思想:回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试。八皇后问题就是回溯算法的典型,第一步按照顺序放一个皇后,然后第二步符合要求放第2个皇后,如果没有位置符合要求,那么就要改变第一个皇后的位置,重新放第2个皇后

    2024年02月05日
    浏览(7)
  • python中级篇1:n皇后问题(回溯算法)

    hello!大家好,我是浪矢秀一。最近经历了许多事情,终于是恢复1次更新了。那么今天呢,我们来学习中级篇,需要学过不少python知识的人来学习。好了,废话不多说,我们进入今天的课程!   在1个n*n的国际象棋棋盘上,放置n个皇后,要求:同1行、同1列、同1斜线上只能有1个皇后。   既然

    2024年02月03日
    浏览(12)
  • 递归算法学习——N皇后问题,单词搜索

    递归算法学习——N皇后问题,单词搜索

    目录 ​编辑 一,N皇后问题 1.题意 2.解释 3.题目接口 4.解题思路及代码 二,单词搜索 1.题意 2.解释 3.题目接口 4.思路及代码 1.题意 按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。 n 皇后问题  研究的是如何将  n  个皇后放置在  n×n  的

    2024年02月09日
    浏览(13)
  • 【算法】递归、回溯、剪枝、dfs 算法题练习(组合、排列、总和问题;C++)

    【算法】递归、回溯、剪枝、dfs 算法题练习(组合、排列、总和问题;C++)

    后面的练习是接着下面链接中的文章所继续的,在对后面的题练习之前,可以先将下面的的文章进行了解👇: 【算法】{画决策树 + dfs + 递归 + 回溯 + 剪枝} 解决排列、子集问题(C++) 思路 题意分析 :要求根据给出的数字,算出合法的括号组成个数。根据题目,我们可以总

    2024年02月22日
    浏览(14)
  • 回溯法求解八皇后问题

    回溯法求解八皇后问题

    问题提出 :八皇后问题是一个古老而著名的问题。该问题是十九世纪著名的数学家高斯1850 提出在 8x8 格的国际象棋上摆放八皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。高斯认为有76种方案。1854年在柏林的象棋杂志

    2023年04月08日
    浏览(10)
  • 八皇后问题(回溯法)

    八皇后问题(回溯法)

    目录 什么是八皇后 八皇后问题怎么解决? 什么是回溯法 回溯法的模板 八皇后问题的核心代码 判断皇后位置是否可行 总体实现代码 每日一句: 种一棵树的最好时间是十年前,其次是现在。 八皇后问题(英文:Eight queens),是由国际西洋棋棋手马克斯·贝瑟尔于1848年提出的

    2023年04月09日
    浏览(5)
  • 回溯法--n皇后问题

    回溯法--n皇后问题

    回溯法有两个模板--子集树、排列树,他们有回溯法的共同特点:深度优先搜索,如果一条路走不通,再退回来(类似递归) 八皇后问题最早是由国际象棋棋手马克斯·贝瑟尔(Max Bezzel)于1848年提出。第一个解在1850年由弗朗兹·诺克(Franz Nauck)给出。并且将其推广为更一般

    2024年02月02日
    浏览(11)
  • 3.2 回溯法—N皇后问题

    3.2 回溯法—N皇后问题

    1. 问题描述 在 n × n ntimes n n × n 的棋盘上摆放 n n n 个皇后,使任意两个皇后都不能处于同一行、同一列或同一斜线上 2. 问题分析 下以求解4皇后问题为例,分析4皇后问题的排列树以及回溯过程: 搜索及回溯过程: 解空间树: 3. 算法设计 1. 算法思想 ①用数组x[]存放皇后的

    2024年02月04日
    浏览(9)
  • 递归求解n皇后问题的解析和求解(矩阵储存版)

    递归求解n皇后问题的解析和求解(矩阵储存版)

    1. n皇后问题问题描述 ​ n皇后问题来源于著名的十九世纪著名数学家提出的八皇后问题。问题为:在8×8的棋盘上摆放八个皇后,皇后之间不能互相攻击,既任意两个皇后不在同一行、同一列,也不再同一斜线上。n皇后则是在八皇后的基础上,将棋盘扩充为n×n,皇后的数量也

    2024年01月19日
    浏览(7)
  • C#八皇后算法:回溯法 vs 列优先法 vs 行优先法 vs 对角线优先法

    目录 1.八皇后算法(Eight Queens Puzzle) 2.常见的八皇后算法解决方案 (1)列优先法(Column-First Method): (2)行优先法(Row-First Method): (3)对角线优先法(Diagonal-First Method): (4)回溯法(Backtracking):        皇后问题是一个古老而著名的问题,它实质上就是使棋

    2024年03月22日
    浏览(6)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包