回溯法求解n皇后问题(复习)
回溯法
回溯法是最常用的解题方法,有“通用的解题法”之称。当要解决的问题有若干可行解时,则可以在包含问题所有解的空间树中,按深度优先的策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该结点为根的子树的搜索,继续查找该结点的兄弟结点,若它的兄弟结点都不包含问题的解,则返回其父结点——这个步骤称为回溯。否则进入一个可能包含解的子树,继续按深度优先的策略进行搜索。这种以深度优先的方式搜索问题的解的算法称为回溯法。它本质上是一种穷举法,但由于在搜索过程中不断略过某些显然不合适的子树,所以搜索的空间大大少于一般的穷举,故它适用于解一些组合数较大的问题。
总结一下:
一、基本定义
回溯法(back track method)是在包含问题的所有可能解的解空间树中,从根结点出发,按照深度优先的策略进行搜索,对于解空间树的某个结点,若满足约束条件,则进入该子树继续搜索,否则将以该结点为根结点的子树进行剪枝。
二、适用范围
可避免搜索所有的可能解,适用于求解组合数较大的问题。
三、n皇后问题
问题:在n x n的棋盘上摆放n个皇后,而且n个皇后中的任意两个是不能处于同一行、同一列、或同一斜线上。
用数组x[i](1≤i≤n)表示n后问题的解。其中x[i]表示皇后i放在棋盘的第i行的第x[i]列。由于不允许将2个皇后放在同一列,所以解向量中的x[i]互不相同。2个皇后不能放在同一斜线上是问题的隐约束。对于一般的n后问题,这一隐约束条件可以化成显约束形式。设2个皇后放置位置为(i,j),(k,l):
显然,棋盘的每一行上可以而且必须摆放一个皇后,所以,n皇后问题的可能解用一个n元向量X=(x1, x2, …, xn)表示,其中,1≤i≤n并且1≤xi≤n,即第i个皇后放在第i行第xi列上
由于两个皇后不能位于同一列上,所以,解向量X必须满足约束条件:
xi≠xj (式1)
若两个皇后摆放的位置分别是(i, xi)和(j, xj),在棋盘上斜率为-1的斜线上,满足条件i-j= xi-xj,在棋盘上斜率为1的斜线上,满足条件i+j= xi+xj,综合两种情况,由于两个皇后不能位于同一斜线上,所以,解向量X必须满足约束条件:
|i-xi|≠|j-xj| (式2)
为了简化问题,下面讨论四皇后问题:
四皇后问题的解空间树是一个完全4叉树,树的根结点表示搜索的初始状态,对应Backtrack(1,x);从根结点到第2层结点对应皇后1在棋盘中第1行的可能摆放位置,从第2层结点到第3层结点对应皇后2在棋盘中第2行的可能摆放位置,依此类推。
完全4叉树,我只画了一部分,完整的应该是除了叶结点,每个内部结点都有四个子结点,k表示层数:
剪枝之后:
回溯法求解4皇后问题的搜索过程:
当然这个图只表示到找到的第一个解,我们知道还有另外一个解。
代码
变量sum记录可行方案个数,初始为0;
n表示皇后个数,由用户输入;
x[]数组保存问题的解,表示皇后i放在棋盘的第i行第x[i]列,初始时各元素都为0,而我们目的是求出有多少组(x[1],x[2],x[3]……x[n])满足摆放条件;
output(int x[])函数作用是输出当前找到的一个可行解,只在搜索到叶节点时才会调用;
Place(int k,int x[])函数作用是,对当前行k以上的所有行(即1到k-1行)逐行进行检查,如果该行与上面任何一行相互攻击(即位于同一对角线上了或同列了:abs(i-k)abs(x[i]-x[k]) || x[i]x[k]),那么返回false,否则返回true;
Backtrack(int k,int x[])函数表示搜索解空间中第k层子树,k>n时,算法搜索至叶节点,得到一个新的n皇后互不攻击放置方案,那么输出该方案,可行方案数sum加1;k<=n时,当前扩展节点是解空间的内部节点,该节点有x[1],x[2],x[3]……x[n]共n个子节点,对每一个子节点,用函数Place检查其可行性,如果可行,以深度优先的方式递归地对可行子树搜索,如果不可行剪枝。
#include <iostream>
#include <cmath>
using namespace std;
// 记录可行方案个数
int sum=0;
// 表示皇后个数,由用户输入
int n;
// 输出当前找到的一个可行解,只在搜索到叶节点时才会调用
int output(int x[]){
int i;
for(i=1;i<=n;i++){
cout << "(" << i << "," << x[i] << ")" << " ";
}
cout << endl;
return 0;
}
// 对当前行k以上的所有行(即1到k-1行)逐行进行检查
bool Place(int k,int x[]){
int i;
for(i=1;i<k;i++){
if(abs(i-k)==abs(x[i]-x[k]) || x[i]==x[k])
return false;
}
return true;
}
// 见上文详解
int Backtrack(int k,int x[]){
int i;
if(k>n){//如果是叶节点,直接输出找到的一个解
output(x);
sum++;
}
else{//内部节点,如果满足约束条件,继续深度搜索 。i代表列数,从1到n
for(i=1;i<=n;i++){
x[k]=i;
if(Place(k,x))
Backtrack(k+1,x);
}
}
}
int main(){
int *x,i;
cout << "输入皇后个数:" << endl;
cin >> n;
cout << endl;
// 数组保存问题的解,表示皇后i放在棋盘的第i行第x[i]列
x=new int[n+1];
// 初始时各元素都为0
for(i=0;i<=n;i++){
x[i]=0;
}
Backtrack(1,x);
cout << endl;
cout << "解的个数:" << sum << endl;
system("pause");
return 0;
}
运行结果
回溯法求解n皇后问题(复习)的更多相关文章
- USACO 1.5.4 Checker Challenge跳棋的挑战(回溯法求解N皇后问题+八皇后问题说明)
Description 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行,每列,每条对角线(包括两条主对角线的所有对角线)上都至多有一个棋子. 列号 0 1 2 3 4 5 6 ...
- 回溯法求解n皇后和迷宫问题
回溯法是一种搜索算法,从某一起点出发按一定规则探索,当试探不符合条件时则返回上一步重新探索,直到搜索出所求的路径. 回溯法所求的解可以看做解向量(n皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...
- 回溯法——求解N皇后问题
问题描写叙述 八皇后问题是十九世纪著名数学家高斯于1850年提出的.问题是:在8*8的棋盘上摆放8个皇后.使其不能互相攻击,即随意的两个皇后不能处在允许行.同一列,或允许斜线上. 能够把八皇后问题拓展 ...
- 0-1背包问题——回溯法求解【Python】
回溯法求解0-1背包问题: 问题:背包大小 w,物品个数 n,每个物品的重量与价值分别对应 w[i] 与 v[i],求放入背包中物品的总价值最大. 回溯法核心:能进则进,进不了则换,换不了则退.(按照 ...
- 算法——八皇后问题(eight queen puzzle)之回溯法求解
八皇后谜题是经典的一个问题,其解法一共有种! 其定义: 首先定义一个8*8的棋盘 我们有八个皇后在手里,目的是把八个都放在棋盘中 位于皇后的水平和垂直方向的棋格不能有其他皇后 位于皇后的斜对角线上的棋 ...
- C++使用回溯法实现N皇后问题的求解
回溯法是个很无聊的死算方法,没什么技巧,写这篇博客主要原因是以前思路不太清晰,现在突然想用回溯法解决一个问题时,无法快速把思路转换成代码. ------------------------------ ...
- 回溯法解决N皇后问题(以四皇后为例)
以4皇后为例,其他的N皇后问题以此类推.所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子.在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平.竖直.以及45度 ...
- 用试探回溯法解决N皇后问题
学校数据结构的课程实验之一. 数据结构:(其实只用了一个二维数组) 算法:深度优先搜索,试探回溯 需求分析: 设计一个在控制台窗口运行的“n皇后问题”解决方案生成器,要求实现以下功能: 由n*n个方块 ...
- 递归回溯法求N皇后问题
问题描述:在一个NN(比如44)的方格中,在每一列中放置一个皇后,要求放置的皇后不在同一行,同一列,同一斜线上,求一共有多少种放置方法,输出放置的数组. 思路解析:从(1,1)开始,一列一列的放置皇后 ...
- 回溯法解n皇后问题
#include<bits/stdc++.h> using namespace std; int n,sum; int c[100]; void search(int cur){ if(c ...
随机推荐
- 最佳实践:4个黄金指标和USE方法
Prometheus鼓励用户监控所有的东西,首先是及时发现问题其次是要能够快速对问题进行定位. 4个黄金指标 4个黄金指标可以在服务级别帮助衡量终端用户体验.服务中断.业务影响等层面的问题. 主要关注 ...
- 【BotR】CLR堆栈遍历(Stackwalking in CLR)
前言 在上一篇文章CLR类型系统概述里提到,当运行时挂起时, 垃圾回收会执行堆栈遍历器(stack walker)去拿到堆栈上值类型的大小和堆栈根.这里我们来翻译BotR里一篇专门介绍Stackwal ...
- while.for循环和基本数据类型内置方法
while循环补充说明 流程控制之for循环 基本数据类型内置方法 内容详细 1.死循环 真正的死循环是一旦执行,Cpu的功耗会急速上升 知道系统采取紧急措施 所以 尽量不要让cpu长时间不断运算. ...
- vscode markdown WYSIWYG 所见即所得编辑和预览
一直使用Typora编写markdown,随着vscode在工作中使用的越来越多,产生了一个想法:能不能在vscode中写markdown,减少软件的成本? 可是vscode官方自带的的markdow ...
- virtualbox的Linux虚拟磁盘大小调整及注意事项
virtualBox 调整磁盘分区 起因 起初安装centos6.3 时,没有修改默认的硬盘空间.只有8G,导致后面安装完zookeeper,jdk之后,在安装mysql发现磁盘空间不足 扩容步骤 1 ...
- RMarkdown进阶操作
技术背景 Markdown大家都比较熟悉了,特别是在写程序文档和写数学公式时,拥有着无与伦比的便利性.同时在前面的一篇博客中我们介绍了使用RMarkdown去写Latex Beamer演示文档的方法, ...
- Linux实战笔记__Ubuntu20.04上搭建Vulhub漏洞环境
安装python3和pip3 安装docker 安装docker-compose 上传解压vulhub-master.zip 启动漏洞环境 进入某漏洞目录,执行docker-compose up -d ...
- 2022最新版超详细的Maven下载配置教程、IDEA中集成maven(包含图解过程)、以及导入项目时jar包下载不成功的问题解决
文章目录 1.maven下载 2.maven环境变量的配置 3.查看maven是否配置成功 4.配置文件的修改 5.IDEA集成maven 6.导入项目时jar包下载不成功的问题解决 maven教程: ...
- 微服务系列之分布式日志 ELK
1.ELK简介 ELK是ElasticSearch+LogStash+Kibana的缩写,是现代微服务架构流行的分布式日志解决方案,旨在大规模服务的日志集中管理查看,极大的为微服务开发人员提供了排查生 ...
- 知识图谱-生物信息学-医学论文(Chip-2022)-BCKG-基于临床指南的中国乳腺癌知识图谱的构建与应用
16.(2022)Chip-BCKG-基于临床指南的中国乳腺癌知识图谱的构建与应用 论文标题: Construction and Application of Chinese Breast Cance ...