回溯法求解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 ...
随机推荐
- 生产环境中使用Kibana
在 Kibana 中使用 X-Pack 使用 X-Pack 安全模块 控制用户通过 Kibana 可以访问哪些 Elasticsearch 数据. 当安装 X-Pack 时,Kibana 用户必须登陆 ...
- 给nsis窗口添加立体阴影
利用SetClassLong函数给nsis窗口添加了阴影,看起来很酷^_^ System::Call `user32::SetClassLong(i$HWNDPARENT,i${GCL_STYLE}, ...
- Apollo 中配置String、Map和List和默认值
摘要:在Apollo 中,配置String.Map和List等类型的信息,同时设置默认值. 综述 随着业务需求的变更,需要在Apollo中配置一个Map<String, List>类型 ...
- 为Azure-云准备一个基于Red Hat 8.x 的虚拟机镜像
由于公司最近要求部分项目上线到Azure云上,要求操作系统使用的Redhat 8.x,而且必须加固 而在Azure官网提供的镜像中,又没有Redhat,于是只有自己自定义Redhat镜像,最后加固,作 ...
- BLS签名算法
前言 [失踪人口回归 (*/ω\*)] 真的好久好久没有更新了,因为自己也还在找方向,但还是把新学的知识记录在博客里.今天要介绍的是BLS签名算法. 一.BLS签名算法简介 BLS签名算法[1]是由斯 ...
- python基础-较复杂数据类型预览
1.初识列表 列表就是队列: 列表是一种有序的,且内容可重复的数据类型: 用list代表列表,也可以用list()定义一个列表,同时定义列表可以直接使用 [ ]: python中列表是 ...
- 常见的 Kerberos 错误消息
常见的 Kerberos 错误消息 问题:All authentication systems disabled; connection refused 原因:此版本的 rlogind 不支持任何验证 ...
- Redis Cluster 原理说的头头是道,这些配置不懂就是纸上谈兵
Redis Cluster 原理说的头头是道,这些配置不懂就是纸上谈兵 Redis Cluster 集群相关配置,使用集群方式的你必须重视和知晓.别嘴上原理说的头头是道,而集群有哪些配置?如何配置让集 ...
- faker
faker是一个生成伪造数据的Python第三方库,可以伪造城市,姓名,文班等各自信息,而且支持中文 安装 pip3 install faker 使用 # 导包 from faker impo ...
- 1.pygame快速入门-创建游戏窗口
简介 pygame是python一个包,专为电子游戏设计#安装 pip3 install pygame #验证安装 # aliens 是pygame内置的一个小游戏,可以启动成功说明pygame安 ...