经典算法-----八皇后问题

news2024/12/29 9:32:56

 目录

前言

八皇后问题

1.问题简介

1.2思路剖析

1.3递归和回溯

代码实现

​编辑

1.递归回溯解决

能否放置数组

完整代码:

2.非递归回溯解决


前言

        今天我们学习一个新的算法,也就是回溯算法,就以八皇后问题作为示例,这是一个非常有意思的问题,下面就一起来看看吧。

八皇后问题

1.问题简介

八皇后问题(英文:Eight queens),是由国际象棋棋手马克斯·贝瑟尔于1848年提出的问题,是回溯算法的典型案例。

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

        高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。如果经过±90度、±180度旋转,和对角线对称变换的摆法看成一类,共有42类。计算机发明后,有多种计算机语言可以编程解决此问题。

看完这个问题描述之后,看上去好像很简单的样子,不就是去摆放棋子嘛,但是当你用编程去写的话就是另外一码事了,压根就不知道从哪里下手。 

1.2思路剖析

还记得在此之前我发布了一个关于迷宫问题的解法吗?(链接:经典算法-----迷宫问题(栈的应用)-CSDN博客)对于迷宫问题是利用栈的回溯算法解决的,当走到死路的时候就往回走,回到上一个位置换一个方向来走,那摆放皇后也是一样的,当下一个无法摆放的时候,那就回到上一个,然后重新摆放上一个皇后再去看看下一个能不能摆放,如果还是不能摆放的话,那就回到上上一个,直到回到第一个皇后,全部重新摆放……

1.3递归和回溯

递归

对于递归算法,我觉得掌握递归是入门数据结构与算法的关键,因为后面学习很多操作涉及到递归,例如链表的一些操作、树的遍历和一些操作、图的dfs、快排、归并排序等等。

而递归的主要特点如下:

  • 自己调用自己
  • 递归通常不在意具体操作,只关心初始条件和上下层的变化关系。
  • 递归函数需要有临界停止点,即递归不能无限制的执行下去。通常这个点为必须经过的一个数。
  • 递归可以被栈替代。有些递归可以优化。比如遇到重复性的可以借助空间内存记录而减少递归的次数

回溯 

算法界中,有五大常用算法:贪心算法、分治算法、动态规划算法、回溯算法、分支界限算法。回溯算法是五大算法之一,虽然有时候复杂度回挺高的,但是回溯算法可以简化去解决很多问题,就向处理套娃问题一样,如果让人去想那就太费脑子了,如果直接去通过递归回溯那计算机回很快解决出来。前面说到的递归,本身来看好像跟八皇后问题的解决没有太大的关系,但是加上回溯就是不一样啦。下面看代码分析吧 

代码实现

 既然都知道了解决算法思路,那我也不装了,直接上代码!!!!!!

1.递归回溯解决

能否放置数组

问题来了,怎么去看这个位置能不能放皇后呢?这里就需要几个标致数组去解决,如下所示:

#define num 8 //定义皇后的数量

int* place = (int*)malloc(sizeof(int) * num);//这个表示是放置皇后的标志
int* y_flag = (int*)malloc(sizeof(int) * num);//这个数组是表示放了皇后之后此时的纵列是能否可以放皇后的标志
int* d1 = (int*)malloc(sizeof(int) * (2 * num - 1));//这个是表示放皇后之后的上对角线能否放的标志
int* d2 = (int*)malloc(sizeof(int) * (2 * num - 1));//这个是表示放皇后后下对角线能否放皇后的标志
//以上的标志数组,其中1表示可以放,0表示不可以放

对于上对角线d1,我们可以去通过这个位置的行位置(第n行)来减掉当前的纵位置(第col列),得到的结果如下图所示,问题来了,我数组的下标不可以是负数呀,所以我们可以在这个前提下加上当前的棋盘长度(长度为num),公式为:n-col+num,最后得到的结果就是下标为0~14的数组啦。

说完了上对角线d1,那就来说下对角线d2 ,对于d2,我们可以这样子去处理,用行位置(n)和纵位置(col)的和就会得到如下图所示的结果,公式为:n+col

完整代码:
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#define num 8 //定义皇后的数量

int* place = (int*)malloc(sizeof(int) * num);//这个表示是放置皇后的标志
int* y_flag = (int*)malloc(sizeof(int) * num);//这个数组是表示放了皇后之后此时的纵列是能否可以放皇后的标志
int* d1 = (int*)malloc(sizeof(int) * (2 * num - 1));//这个是表示放皇后之后的上对角线能否放的标志
int* d2 = (int*)malloc(sizeof(int) * (2 * num - 1));//这个是表示放皇后后下对角线能否放皇后的标志
//以上的标志数组,其中1表示可以放,0表示不可以放

//如果放满了就进行打印
void print(int *count) {
	*count+=1;//统计次数
	printf("第%d次:\n", *count);
	for (int x = 0; x < num; x++) {
		for (int y = 0; y < num; y++) {
			if (place[x] == y)
				printf("Q");
			printf("#");
		}
		printf("\n");
	}
	printf("\n");
}

//执行函数
void generate(int n,int *count) {
	//每一个皇后有8种放置方法
	for (int col = 0; col < num; col++) {
		//如果可以放置的话,那就是这个位置的纵向为1,上对角线和下对角线也为1,就是可以放置
		if (y_flag[col] && d1[n - col + 7] && d2[n + col]) {
			//可以放置的话,那么这4个标志数组就宣告这个位置被占领了
			place[n] = col;
			y_flag[col] = 0;//定义为0,就是这个位置不能放了
			d1[n - col + 7] = 0;
			d2[n + col] = 0;
			//如果没有放完,就进行递归放下一个
			if (n < num-1)
				generate(n + 1,count);
			//如果放完了,那就打印这个结果
			else
				print(count);
			//放完之后就进行回溯,把当前皇后的位置抹除
			place[n] = 0;
			y_flag[col] = 1;
			d1[n - col + 7] = 1;
			d2[n + col] = 1;
		}
	}
}

int main() {
	//标志数组初始化
	memset(place, 0, sizeof(place));
	memset(y_flag, 1, sizeof(y_flag));
	memset(d1, 1, sizeof(d1));
	memset(d2, 1, sizeof(d2));
	
	int count = 0;//统计
	generate(0,&count);
}

2.非递归回溯解决

#include<string.h>
#include<stdio.h>
#include<stdlib.h>
//打印结果
void print(int* count,int* place,int num) {
	*count += 1;
	printf("第%d种:\n", *count);
	for (int i = 0; i < num; i++) {
		for (int j = 0; j < num; j++) {
			if (place[i] == j)
				printf("□");
			else
				printf("■");
		}
		puts("");
	}
	puts("");
}

void generate(int num,int *count,int* place,int *flag,int *d1,int *d2) {
	int n = 0;
	int col = 0;
	while (1)
	{
		for (; col < num; 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;
				break;
			}
		}
		//如果找到了放置的位置col < num
		if (col < num) {
			//如果没有放完,那就进入到放下一层
			if (n < num - 1) {
				col = 0;
				n++;
				continue;
			}
			//如果放完了,那就打印操作
			else
				print(count, place, num);
		}
		//回溯到上一层
		else {
			n--;
			col = place[n];
		}
		//抹除操作
		place[n] = 0;
		flag[col] = 1;
		d1[n - col + 7] = 1;
		d2[n + col] = 1;
		col++;
		//回溯到不能回溯为止,退出结束循环
		if (n == 0 && col == num)
			break;
	}
}

int main() {
	int num;
	int count = 0;//统计
	printf("输入要放的皇后:");
	scanf("%d", &num);
	//空间开辟,初始化
	int* place = (int*)malloc(sizeof(int) * num);
	int* flag = (int*)malloc(sizeof(int) * num);
	int* d1 = (int*)malloc(sizeof(int) * (2 * num - 1));
	int* d2 = (int*)malloc(sizeof(int) * (2 * num - 1));
	memset(place, 0, sizeof(int)*num);
	memset(flag, 1, sizeof(int)*num);
	memset(d1, 1, sizeof(int)* (2 * num - 1));
	memset(d2, 1, sizeof(int)* (2 * num - 1));

	generate(num,&count, place,flag,d1,d2);
}

运行结果:

以上就是这个问题的解决方法了,你们同样的可以去试一下用数据结构栈来解决这个问题,我就不多说了哈,你们学会了吗?

分享一张壁纸: 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1060052.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑指offer——JZ25 合并两个排序的链表 解题思路与具体代码【C++】

一、题目描述与要求 两个链表的第一个公共结点_牛客题霸_牛客网 (nowcoder.com) 题目描述 输入两个无环的单向链表&#xff0c;找出它们的第一个公共结点&#xff0c;如果没有公共节点则返回空。&#xff08;注意因为传入数据是链表&#xff0c;所以错误测试数据的提示是用其…

C++的对像生存期

栈 栈由操作系统分配管理&#xff0c;也就是它是规整的&#xff0c;内存的大小在申请之后不会发生变化。因此&#xff0c;它不会出现碎片化&#xff0c;并且读取速度非常的快 例如&#xff1a;经常声明的局部变量&#xff0c;一些基本数据类型&#xff0c;如int ,double, char…

力扣 -- 518. 零钱兑换 II(完全背包问题)

解题步骤&#xff1a; 参考代码&#xff1a; 未优化代码&#xff1a; class Solution { public:int change(int amount, vector<int>& coins) {int ncoins.size();//多开一行&#xff0c;多开一列vector<vector<int>> dp(n1,vector<int>(amount1…

LLVM IR 文档 专门解释 LLVM IR

https://llvm.org/docs/LangRef.html#phi-instruction

Linux网络编程:详解https协议

目录 一. https协议概述 二. 中间人截获 三. 常见的加密方法 3.1 对称加密 3.2 非对称加密 四. 数据摘要和数据签名的概念 五. https不同加密方式的安全性的探究 5.1 使用对称加密 5.2 使用非对称加密 5.3 非对称加密和对称加密配合使用 六. CA认证 七. 总结 一.…

JWFD开源工作流大模型设计器

JWFD开源工作流大模型设计器&#xff0c;把流程图的拓扑结构从几十个节点扩展到数千个节点&#xff0c;就不是使用绘图器的模式了&#xff0c;需要开发一个模型生成器了&#xff0c;尝试做一下大模型&#xff0c;赶赶时髦啊

openwrt安装与旁路由 以玩客云为例

鉴于安了wfnb/onecloud 23年的bata版本 结果发现进入docker 连make config apt yum apk curl等命令都没有……而且curl下载很慢 得选6.0哪个版本 反正就是 安不了istore 所以 直接刷人家的成品算了 为什么要使用软路由、旁路由 普通的路由器往往集无线信号转发、网关、DNS 服…

JMeter工具的介绍,安装

一、本文学习目标 1、能知道JMeter的优缺点 2、能掌握JMeter的安装流程 3、能掌握JMeter线程组的设置 4、能掌握JMeter参数化的使用 5、能掌握JMeter直连数据库操作 6、能掌握JMeter的断言. 二、JMeter简介 &#xff08;1&#xff09;Jmeter详细介绍 **JMeter&#xff08;A…

RTC 时间、闹钟

实时时钟RTC是一个独立的定时器。RTC模块拥有一个连续计数的计数器&#xff0c;在软件配置下&#xff0c;可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。 在掉电情况下 RTC仍可以独立运行 只要芯片的备用电源…

MySQL数据库基础回顾与复习

MySQL数据库 一、原理定义概念 定义 数据库(Database)是按照数据结构来组织、存储和管理数据的建立在计算机存储设备上的仓库 数据库是长期储存在计算机内、有组织的、可共享的数据集合 分类&#xff1a; &#xff08;1&#xff09;非结构化数据&#xff1a; 数据相对来讲没…

QFluentWidgets: 基于 C++ Qt 的 Fluent Design 组件库

简介 QFluentWidgets 是一个基于 Qt 的 Fluent Designer 组件库&#xff0c;内置超过 150 个开箱即用的 Fluent Designer 组件&#xff0c;支持亮暗主题无缝切换和自定义主题色。搭配所见即所得的 Fluent Designer 软件&#xff0c;只需拖拖拽拽&#xff0c;不用编写一行 QSS&…

腾讯云服务器简介和使用流程

腾讯云服务器在云服务器CVM或轻量应用服务器页面自定义购买价格比较贵&#xff0c;但是自定义购买云服务器CPU内存带宽配置选择范围广&#xff0c;活动上购买只能选择固定的活动机&#xff0c;选择范围窄&#xff0c;但是云服务器价格便宜比较省钱。腾讯云服务器网来详细说下腾…

driver.js 扩展下次“不再提示”功能

文档地址&#xff1a;https://github.com/kamranahmedse/driver.js 官方demo&#xff1a;https://kamranahmed.info/driver.js/ /*** Title: 页面引导 ……* Author: JackieZheng* Date: 2023-08-16 10:43:31* LastEditTime: 2023-08-16 10:55:08* LastEditors:* Description:*…

找不到msvcp110.dll是什么意思?总结msvcp110.dll丢失修复方法分享

随着电脑技术的不断发展&#xff0c;我们也会遇到各种各样的问题。最近&#xff0c;我就遇到了一个问题&#xff1a;电脑丢失msvcp110.dll的困扰。这个问题让我深感无奈&#xff0c;但同时也让我学到了很多关于电脑维修和系统修复的知识。在这篇文章中&#xff0c;我将分享我的…

前端JavaScript入门到精通,javascript核心进阶ES6语法、API、js高级等基础知识和实战 —— Web APIs(五)

思维导图 Bom操作 一、Window对象 1.1 BOM(浏览器对象模型) <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"vi…

macOS Sonoma 正式版系统已发布,macos14值得更新吗

北京时间9月27日macOS Sonoma 正式版系统发布&#xff0c;为 Mac 带来一系列丰富新功能&#xff1a;优化小组件、升级视频会议、沉浸式游戏体验等&#xff0c;最新macos14值得更新吗&#xff1f;这里根据我一个月的试用beta版本体验来分享一下。 我使用的是M1芯片的MacBook air…

Java架构师功能设计和架构设计

目录 1 架构设计理念1.1 架构定义1.2 文档编写1.3 维护和改进1.4 验证实现1.5 总结 2 深入理解和认识架构设计2.1 架构设计关注哪些东西2.2 架构设计是一系列的活动不断演化和完善的过程2.3 架构设计跨越软工的全流程2.3.1 软工的全流程的原因 3 功能设计概念4 理解和认识功能设…

【Vue3】定义全局变量和全局函数

// main.ts import { createApp } from vue import App from ./App.vue const app createApp(App)// 解决 ts 报错 type Filter {format<T>(str: T): string } declare module vue {export interface ComponentCustomProperties {$filters: Filter,$myArgs: string} }a…

openwrt使用教程

openwrt 插件安装 首先 我们需要明确自己什么版本的cpu 进入docker 然后 cat /proc/cpuinfo# 查看CPU信息 uname -m# 查看CPU架构 cat /proc/meminfo# 查看内存使用情况 df -h# 查看磁盘的使用率 uname -a# 查看内核信息 opkg print-architecture# 可接受的架构arm a5 比较奇…

Maven超细致史上最全Maven下载安装配置教学(2023更新...全版本)建议收藏...赠送IDEA配置Maven教程

Maven安装与配置 Maven 的主要目标是让开发人员能够在最短的时间内了解开发工作的完整状态。为了实现这一目标&#xff0c;Maven 处理了几个关注领域&#xff1a; 简化构建过程 提供统一的构建系统 提供优质的项目信息 鼓励更好的发展实践 基于项目对象模型 (POM&#xff0…