回溯法解决四皇后问题

以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个节点,显而易见,哪一个方法更有效。

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

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

 1 #include<stdio.h>
 2
 3 int count = 0;
 4 int isCorrect(int i, int j, int (*Q)[4])
 5 {
 6     int s, t;
 7     for(s=i,t=0; t<4; t++)
 8         if(Q[s][t]==1 && t!=j)
 9             return 0;//判断行
10     for(t=j,s=0; s<4; s++)
11         if(Q[s][t]==1 && s!=i)
12             return 0;//判断列
13     for(s=i-1,t=j-1; s>=0&&t>=0; s--,t--)
14         if(Q[s][t]==1)
15             return 0;//判断左上方
16     for(s=i+1,t=j+1; s<4&&t<4;s++,t++)
17         if(Q[s][t]==1)
18             return 0;//判断右下方
19     for(s=i-1,t=j+1; s>=0&&t<4; s--,t++)
20         if(Q[s][t]==1)
21             return 0;//判断右上方
22     for(s=i+1,t=j-1; s<4&&t>=0; s++,t--)
23         if(Q[s][t]==1)
24             return 0;//判断左下方
25
26     return 1;//否则返回
27 }
28
29 void Queue(int j, int (*Q)[4])
30 {
31     int i,k;
32     if(j==4){//递归结束条件
33         for(i=0; i<4; i++){
34                 //得到一个解,在屏幕上显示
35             for(k=0; k<4; k++)
36                 printf("%d ", Q[i][k]);
37             printf("\n");
38         }
39         printf("\n");
40         count++;
41         return ;
42     }
43     for(i=0; i<4; i++){
44         if(isCorrect(i, j, Q)){//如果Q[i][j]可以放置皇后
45             Q[i][j]=1;//放置皇后
46             Queue(j+1, Q);//递归深度优先搜索解空间树
47             Q[i][j]=0;//这句代码就是实现回溯到上一层
48         }
49     }
50 }
51
52 int main()
53 {
54     int Q[4][4];
55     int i, j;
56     for(i=0; i<4; i++)
57         for(j=0; j<4; j++)
58             Q[i][j] = 0;
59     Queue(0, Q);
60     printf("The number of the answers are %d\n", count);
61     return 0;
62 }
时间: 2024-08-02 04:04:30

回溯法解决四皇后问题的相关文章

AI -- 回溯法解决四皇后问题

AI -- 回溯法解决四皇后问题 回溯法 四皇后 C语言 问题描述 在 4*4 的棋盘上无冲突的摆放 4 个皇后,无冲突是指一个皇后所在位置的水平.竖直以及斜线上不能出现其他的皇后,其他的 n 皇后问题以此类推 解决方法 按行来摆放棋子,下一行的摆放满足于与上一行的棋子没有冲突,否则就返回上一步走其他的路线,这就是所谓的回溯法 详细说明 在第一行有四种可能,选择第一个位置放上皇后 第二行原本可以有四种可能摆放,但是第一第二个已经和第一行的皇后冲突了,因此只剩下第三第四个格子了,先选择第三个格子

华为机试—N皇后问题(高级题160分:两种回溯法解决 吐血整理)

一.问题描述: 在n×n格的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上. 输入: 给定棋盘的大小n (n ≤ 13) 输出: 输出有多少种放置方法. 二.解题思路: 要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行.同一列.同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇

回溯法解决迷宫问题

现在有迷宫地图:(回溯法) 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 0 1 1 1 1 1 1 1 将迷宫地图存于文件中,将文件里的信息依次读入到二维数组中,设置入口,先将

回溯法解决八皇后问题

八皇后问题是学习回溯算法时不得不提的一个问题,用回溯算法解决该问题逻辑比较简单. 下面用java版的回溯算法来解决八皇后问题. 八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例.该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 思路是按行来规定皇后,第一行放第一个皇后,第二行放第二个,然后通过遍历所有列,来判断下一个皇后能否放在该列.直到所有皇后都放完,或者放哪

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

学校数据结构的课程实验之一. 数据结构:(其实只用了一个二维数组) 算法:深度优先搜索,试探回溯 需求分析: 设计一个在控制台窗口运行的“n皇后问题”解决方案生成器,要求实现以下功能: 由n*n个方块排成n行n列的正方形称为n元棋盘.如果两个皇后位于n元棋盘上的同一行.同一列或同一对角线上,则称它们在互相攻击.现要找出使棋盘上n个皇后互不攻击的布局. 编制程序解决上述问题,以n=6运行程序,输出结果. 算法解释: 首先试探当前行第一个可用的位置(列.对角线没有被占领),摆放皇后之后,试探下一行的

八皇后之回溯法解决[转]

问题描述: 要在8*8的国际象棋棋盘中放8个皇后,使任意两个皇后都不能互相吃掉.规则是皇后能吃掉同一行.同一列.同一对角线的棋子.如下图即是两种方案: . 解决方案: 8*8的棋盘要摆放8个皇后,且不能同行同列同对角线,那么每行必定会有一个皇后.我们可以设一个数组a用来存放每一行皇后的位置,元素值表示第几列(如a[1]=5表示第一行的皇后处于第五个格).然后只需要求出数组a的值 问题就解决了,下面介绍三种回溯解法: 1.八个for循环.用枚举的办法,八个for循环分别枚举每一行的8个位置,但是我

回溯法解决八皇问题

把八个皇后放在一个8*8的棋盘上面,要求同一行.同一列.同一对角线不能有两个皇后. 思路:关键在于判定两个皇后是否在同一行.同一列或同一对角线上.这里,棋盘下标从1开始算起.观察发现:若是在同一行,则行号相同:若在同一列,则列号相同:若在同一“/”对角线,则行列值之和相同:若是在同一“\”对角线,则行列值之差相同.考虑到每行仅有一个皇后,设一维数组a[1...8]表示皇后的位置:第i行第j列放置皇后,则a[i]=j,即下标是行数,值是列数.判断皇后是否安全,即检查同一列.同一对角线是否已经有皇后

回溯法解决N皇后问题

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

回溯法——n后问题

问题描述: 在n*n的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于在n*n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线. 盲目的迭代枚举: 1 /* 2 *作者:xymaqingxiang 3 *说明:八皇后--盲目迭代法 4 *分析:通过8重循环模拟搜索空间中的8^8个状态,从中找出满足约束条件的可行性方案 5 *日期:2014-05-15 6 */ 7 #include <iostream>