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

要求编程求出符合要求的情况的个数。四皇后问题有很多种解法,这里主要介绍一种经典的解决方法:回溯法

回溯法的基本思想是:可以构建出一棵解空间树,通过探索这棵解空间树,可以得到四皇后问题的一种或几种解。这样的解空间树有四棵

在如上图所示的4×4的棋盘上,按列来摆放棋子,首先因为皇后棋子不能在同一列,所以先排除有2个或2个以上的棋子在同一列的情况,所以第一个棋子在第一列有4种摆放方法(第1列第1行,第1列第2行,第1列第3行,第1列第4行),同样第二个棋子在第二列有4种,同样第三个棋子在第三列有4种,同样第四个棋子在第四列有4种,所以进行简单的排除不在同一列的情况后,还有4×4×4×4=256种可能,但是在这256种可能里,依然存在比如棋子在同一行,或在45度斜线上的情况出现。另一个角度思考,所有的满足四皇后问题的摆放方式一定都存在于这256种情况之中。简单的理解就是:这256种棋盘局面包含了所有满足4皇后问题的解,但是不包含全部的棋盘局面。

下面是解空间树的示例(以上一段的按列摆放的方式来进行示例讲解),其中第i层的棋盘局面是在第i-1层的棋盘局面演化而来的(1<i<4)

上面的图片是以第一个棋子在第一列的第一行而派生出的一个解空间树,最后一层会有64中结局面,同理在以第一个棋子在第一、列的第二/三/四行都分别可以派生出一个解空间树,最后一层都会有64中局面,所以有4棵解空间树,每一棵最终有64个局面,所以一共有4×64=256种局面

可以用上面的方法穷举出所有的解,再遍历穷举的所有结果找出所有符合四皇后问题的解,但是这样会很浪费。所以这里可以用到回溯法,在构建解空间树的途中进行深度优先探索,当探索到某一种棋盘局面一定不是四皇后问题的解的时候(比如出现任意两个或两个以上的棋子在同一行/同一列/45度斜线上),就可以判断这个节点向下派生出的解空间树的节点也一定不是四皇后问题的解,这样就可以避免大量的无用功。

比如上图中第二行的第一个节点出现了两个棋子在同一行的情况,所以可以判断出这个节点以及这个节点向下派生出的所有节点就不再有必要进行遍历了,这样就会避免4+4×4次的完全无用功的遍历,就会大大的节省时间,再去探索第二行的第二个节点……其他的同理。

这样,如果能够成功遍历到叶子节点,并且判断该叶子节点的局面就是符合4皇后问题的,那么这个节点局面就代表一个合法的四皇后问题的解。下面的图片就代表找到的一个合法的解的过程(注意图片中,虚线代表排除,黑实线代表继续向下探索)     以上图为例,当在第i层出现非法的棋盘局面时,就跳回第i-1层,继续探索第i-1层的那个节点的下一个分支;或者在第4层探索到合法的局面就进行记录并跳回上一层,继续探索下一个分支。其他三个解空间树同理。

以上图为例,就单看探索的第四层节点的个数。使用回溯法,就只需探索第4层中的4个节点,而如果使用穷举法,就要探索玩第4层的所有64个节点,显而易见,哪一个方法更有效。

其实在解决四皇后问题的时候,并不一定要真的构建出这样的一棵解空间树,它完全可以通过一个递归回溯来模拟。所谓的解空间树只是一个逻辑上的抽象。当然也可以用树结构来真实的创建出一棵解空间树,不过那样会比较浪费空间资源,也没有那个必要

解决四皇后问题的算法描述如下

#include<stdio.h>

int count = 0;
int isCorrect(int i, int j, int (*Q)[4])
{
int s, t;
for(s=i,t=0; t<4; t++)
if(Q[s][t]==1 && t!=j)
return 0;//判断行
for(t=j,s=0; s<4; s++)
if(Q[s][t]==1 && s!=i)
return 0;//判断列
for(s=i-1,t=j-1; s>=0&&t>=0; s--,t--)
if(Q[s][t]==1)
return 0;//判断左上方
for(s=i+1,t=j+1; s<4&&t<4;s++,t++)
if(Q[s][t]==1)
return 0;//判断右下方
for(s=i-1,t=j+1; s>=0&&t<4; s--,t++)
if(Q[s][t]==1)
return 0;//判断右上方
for(s=i+1,t=j-1; s<4&&t>=0; s++,t--)
if(Q[s][t]==1)
return 0;//判断左下方 return 1;//否则返回
} void Queue(int j, int (*Q)[4])
{
int i,k;
if(j==4){//递归结束条件
for(i=0; i<4; i++){
//得到一个解,在屏幕上显示
for(k=0; k<4; k++)
printf("%d ", Q[i][k]);
printf("\n");
}
printf("\n");
count++;
return ;
}
for(i=0; i<4; i++){
if(isCorrect(i, j, Q)){//如果Q[i][j]可以放置皇后
Q[i][j]=1;//放置皇后
Queue(j+1, Q);//递归深度优先搜索解空间树
Q[i][j]=0;//这句代码就是实现回溯到上一层
}
}
} int main()
{
int Q[4][4];
int i, j;
for(i=0; i<4; i++)
for(j=0; j<4; j++)
Q[i][j] = 0;
Queue(0, Q);
printf("The number of the answers are %d\n", count);
return 0;
}

回溯法解决N皇后问题(以四皇后为例)的更多相关文章

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

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

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

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

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

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

  4. Python基于回溯法解决01背包问题实例

    Python基于回溯法解决01背包问题实例 这篇文章主要介绍了Python基于回溯法解决01背包问题,结合实例形式分析了Python回溯法采用深度优先策略搜索解决01背包问题的相关操作技巧,需要的朋友 ...

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

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

  6. 回溯算法——解决n皇后问题

    所谓回溯(backtracking)是通过系统地搜索求解问题的方法.这种方法适用于类似于八皇后这样的问题:求得问题的一个解比较困难,但是检查一个棋局是否构成解很容易. 不多说,放上n皇后的回溯问题代码 ...

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

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

  8. C语言回溯算法解决N皇后问题

    回溯算法的模型是 x++, not satisfy ? x-- : continue. 代码中x作列号,y[x]保存第x列上皇后放置的位置. #include<stdio.h> #incl ...

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

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

随机推荐

  1. __get().__set.__isset,__unset魔术方法

    一般来说,总是把类的属性定义为 private .这更符合现实的逻辑. 但是对属性的读取和赋值操作非常频繁的,因此在PHP中,预定义了两魔术方法 "__get()"用来获取私有成员属性值的,只有一个参 ...

  2. SQL 多表一起查询的语句总结

    sql 同时查询多个表 可以使用连表查询比如使用join sql 同时查询多个表 可以使用连表查询 比如 使用join select s1.*,s2.* from s1 left join s2 on ...

  3. IE盒模型

    IE5.5及更早的版本使用的是IE盒模型,在在IE6及以上版本的浏览器中,浏览器支持一种解决了这种差异的可选的渲染模式,也开始遵循标准模式. IE盒模型和W3C盒模型的差异: IE盒模型,块元素的实际 ...

  4. 2-python学习——hello world

    "hello world"是编程界一个经久不衰的例子,几乎所有语言的学习教程都把它当做第一个程序的范例.学习的过程就是再造轮子的过程,千万不要以为有人做过的,就不去学习了. hel ...

  5. 初识hibernate小案例

    使用hibernate前需要导入相关JAR包. 1.它可以接受词文法语言描述,并能产生识别这些语言的语句的程序 2.是一个Java的XML API,类似于jdom,用来读写XML文件的 3.支持注解配 ...

  6. 数据库Error:The ScriptCollection in ScriptName not find

    System.InvalidOperationException: The ScriptCollection in ScriptName not find 在 WMI.SQL.HELPER.CONFI ...

  7. poj 1220(短除法)

    http://poj.org/problem?id=1220 题意:进制转换,把a进制转换为b进制. 如果数据不大的话,那么这个题还是很简单的,但这个题就是数据范围太大,所以这里可以采用短除法来做. ...

  8. 手动编译并运行Java项目的过程

    现在Java开发基本上就是IDE调试,如果跨平台打个jar包过去运行一般就可以了,但是有些情况比如需要引入外部依赖的时候,这个时候是不能直接运行的,还需要引入一些外部的参数,并不是简单的javac和j ...

  9. cxTreeList 控件说明

    树.cxTreeList 属性: Align:布局,靠左,靠右,居中等 AlignWithMargins:带边框的布局 Anchors:停靠 (akTop上,akBottom下,akLeft左,akR ...

  10. reportng的使用

    1.首先安装testng 2.下载reportng jar包 http://pan.baidu.com/s/1i3KdlQH 3.添加到project build path 注意:需要同时引入goog ...