回溯法

回溯法是最常用的解题方法,有“通用的解题法”之称。当要解决的问题有若干可行解时,则可以在包含问题所有解的空间树中,按深度优先的策略,从根节点出发搜索解空间树。算法搜索至解空间树的任一结点时,总是先判断该结点是否肯定不包含问题的解。如果肯定不包含,则跳过对以该结点为根的子树的搜索,继续查找该结点的兄弟结点,若它的兄弟结点都不包含问题的解,则返回其父结点——这个步骤称为回溯。否则进入一个可能包含解的子树,继续按深度优先的策略进行搜索。这种以深度优先的方式搜索问题的解的算法称为回溯法。它本质上是一种穷举法,但由于在搜索过程中不断略过某些显然不合适的子树,所以搜索的空间大大少于一般的穷举,故它适用于解一些组合数较大的问题。

总结一下:

一、基本定义

回溯法(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皇后问题(复习)的更多相关文章

  1. USACO 1.5.4 Checker Challenge跳棋的挑战(回溯法求解N皇后问题+八皇后问题说明)

    Description 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行,每列,每条对角线(包括两条主对角线的所有对角线)上都至多有一个棋子. 列号 0 1 2 3 4 5 6 ...

  2. 回溯法求解n皇后和迷宫问题

    回溯法是一种搜索算法,从某一起点出发按一定规则探索,当试探不符合条件时则返回上一步重新探索,直到搜索出所求的路径. 回溯法所求的解可以看做解向量(n皇后坐标组成的向量,迷宫路径点组成的向量等),所有解 ...

  3. 回溯法——求解N皇后问题

    问题描写叙述 八皇后问题是十九世纪著名数学家高斯于1850年提出的.问题是:在8*8的棋盘上摆放8个皇后.使其不能互相攻击,即随意的两个皇后不能处在允许行.同一列,或允许斜线上. 能够把八皇后问题拓展 ...

  4. 0-1背包问题——回溯法求解【Python】

    回溯法求解0-1背包问题: 问题:背包大小 w,物品个数 n,每个物品的重量与价值分别对应 w[i] 与 v[i],求放入背包中物品的总价值最大. 回溯法核心:能进则进,进不了则换,换不了则退.(按照 ...

  5. 算法——八皇后问题(eight queen puzzle)之回溯法求解

    八皇后谜题是经典的一个问题,其解法一共有种! 其定义: 首先定义一个8*8的棋盘 我们有八个皇后在手里,目的是把八个都放在棋盘中 位于皇后的水平和垂直方向的棋格不能有其他皇后 位于皇后的斜对角线上的棋 ...

  6. C++使用回溯法实现N皇后问题的求解

    回溯法是个很无聊的死算方法,没什么技巧,写这篇博客主要原因是以前思路不太清晰,现在突然想用回溯法解决一个问题时,无法快速把思路转换成代码. ------------------------------ ...

  7. 回溯法解决N皇后问题(以四皇后为例)

    以4皇后为例,其他的N皇后问题以此类推.所谓4皇后问题就是求解如何在4×4的棋盘上无冲突的摆放4个皇后棋子.在国际象棋中,皇后的移动方式为横竖交叉的,因此在任意一个皇后所在位置的水平.竖直.以及45度 ...

  8. 用试探回溯法解决N皇后问题

    学校数据结构的课程实验之一. 数据结构:(其实只用了一个二维数组) 算法:深度优先搜索,试探回溯 需求分析: 设计一个在控制台窗口运行的“n皇后问题”解决方案生成器,要求实现以下功能: 由n*n个方块 ...

  9. 递归回溯法求N皇后问题

    问题描述:在一个NN(比如44)的方格中,在每一列中放置一个皇后,要求放置的皇后不在同一行,同一列,同一斜线上,求一共有多少种放置方法,输出放置的数组. 思路解析:从(1,1)开始,一列一列的放置皇后 ...

  10. 回溯法解n皇后问题

    #include<bits/stdc++.h> using namespace std; int n,sum; int c[100]; void search(int cur){ if(c ...

随机推荐

  1. Linux 下模拟制作块设备并挂载

    Linux 下模拟制作块设备并挂载 作者:Grey 原文地址: 博客园:Linux 下模拟制作块设备并挂载 CSDN:Linux 下模拟制作块设备并挂载 环境 CentOS-7 下载地址:下载 Cen ...

  2. Vue中组件化编码使用、实现组件之间的参数传递(实战练习二)

    上一章节实现的是静态页面的设计.这一章节实现将数据抽取出来.通过组件间参数的传递来实现 上一章节链接地址:https://blog.csdn.net/weixin_43304253/article/d ...

  3. 齐博X1-栏目的调用1

    本节来说明下系统提供的几个栏目调用的方法 一节我们制作了一个公共导航,本节我们在首页index中演示下栏目的相关调用 至于其他的数据内容,参考第二季的标签调用即可,直接{qb:tag}调用就可以调用出 ...

  4. golang开发一个简单的grpc

    0.1.索引 https://waterflow.link/articles/1665674508275 1.什么是grpc 在 gRPC 中,客户端应用程序可以直接调用不同机器上的服务器应用程序上的 ...

  5. C#中的装箱和拆箱

    什么是装箱和拆箱 装箱(boxing)和拆箱(unboxing)是C#类型系统的核心概念.是不同于C与C++的新概念!,通过装箱和拆箱操作,能够在值类型和引用类型中架起一做桥梁. 换言之,可以轻松的实 ...

  6. (二)Three光线检测-实现摄像机向鼠标点击位置滑动动画

    (二)Three.js光线检测 摘要:使用three.js中的光线检测 Raycaster() ,实现一下效果: 通过点击处的坐标,修改摄像机位置,实现摄像机由远及近的过渡动态效果(由远景到近景) 1 ...

  7. Sublime Text怎样自定义配色和主题

    一.自定义配色方案 1 基础知识 配色方案[Color Scheme]文件保存在以下路径[ST安装目录]: "D:\Program Files\Sublime Text\Packages\C ...

  8. JS逆向实战8——某网实战(基于golang-colly)

    其实本章算不上逆向教程 只是介绍golang的colly框架而已 列表页分析 根据关键字搜索 通过抓包分析可知 下一页所请求的参数如下 上图标红的代表所需参数 所以其实我们真正需要的也就是Search ...

  9. 云原生之旅 - 8)云原生时代的网关 Ingress Nginx

    前言 当我们在Kubernetes部署的服务需要暴露给外部用户使用时,有三种选择:LoadBalancer,NodePort, Ingress. LoadBalancer类型得结合各个Cloud Pr ...

  10. 本人常用的sed命令用法

    如果使用sed命令修改文件,需要为sed命令指定[-i]选项(i,insert表示插入指令),下面是本人常用到的几种场景: 1. 在文件最后一行的下一行添加配置 如:在配置文件/etc/profile ...