八皇后问题(回溯算法)

来源:互联网 发布:外设与cpu数据交换方式 编辑:程序博客网 时间:2024/05/18 09:26

        八皇后问题是古老的问题,十八世纪由一个国际象棋手提出的,即在一个8 * 8 的国际象棋盘上,放置八个皇后,使它们不能相互攻击到。即不能处于同一行,同一列,也不能处于同一条斜线上,问有多少种摆法。八皇后问题是经典的回溯算法问题,后人利用计算机,算出了8 * 8 的棋盘上能摆出92种,而后又提出了N皇后问题。

        本人不太擅长算法,弄了几天,才弄懂这个算法,并且把自己对回溯的学习记录下来。

        首先看看题目说的,需要n * n的棋盘上放置n 个皇后,其在某个位置A (x, y)是否安全的判断为,对于所有已摆放的皇后位置B (x, y), ∀B(i) ,

B(i).x ≠ A.x ∧ B(i).y ≠ A.y 表示不在同一列,同一行;

B(i).x + B(i).y ≠ A.x + A.y 表示不在同一条斜线(右上到左下方向)上;

B(i).x - B(i).y ≠ A.x - A.y 表示不在同一条斜线(左上到右下方向)上;

        而且每放下一个皇后,就要判断所有已放置的皇后位置是否能攻击到,那么我们需要一个存储空间来存储所有已放置的皇后位置信息,进行迭代,

        可以选用数组,也可以选用矩阵;但我们大可不用矩阵,毕竟棋盘是n * n 的,且每个皇后不可能在同一行摆放,或者不可能再同一列摆放,于是只使用一个一维

数组,便能存储八皇后位置。我们定义数组queen (n)的一个下标索引x ∈(0,1,2..n-1)表示棋盘的某一列,那么其值queen (x) 即存储一个皇后在此列中哪一行摆放。


接着分析一下算法流程:

当我们放置一个皇后时迭代此列上所有的行,且所有的行都要测试,以便我们找的所有的解。

当某行测试通过时,可以继续迭代下一列的皇后摆放位置,直到列标为n-1,此时即可确定一种摆放方法。;

当某一行测试不通过时,继续下一行的迭代,直到行标为n-1。


如此进行回溯,直到所有的解空间树都被遍历一遍。

全局变量:

_n 表示用户输入的棋盘大小,默认为8.

queen 用于存储n个皇后的位置,由 _n 确定大小。

maxnum 用于存储找到的所有解数。

函数:

主要的回溯函数为loop (),传入参数表示从_sta_col这一列开始放置后面的皇后,当放置到最后n-1列并检测安全后(此时会再次递归调用loop (n)),返回true,否则返回false,继续进行迭代。

check () 函数用于检测已放置的皇后与放置在参数(_row, _col)处的皇后是否有冲突,有则返回false,表示不安全。

main () 只做简单的用户输入处理,并进行一定初始化,之后调用loop (),从0列开始计算。

命令格式: main <n>, 参数n > 0。

/*author : yezdate : 2015/5/17describe : eight queen algorithm*/#include <stdio.h>#include <memory.h>#include <stdlib.h>#include <stdbool.h>// default valueint _n = 8;int* queen;int maxnum = 0;bool loop (int);bool check (int, int);bool loop (int _sta_col) {int i = 0;if (_sta_col == _n) {maxnum ++;return true;}for (; i < _n; i ++) { // iterate row if (check (i, _sta_col)) {queen [_sta_col] = i;loop (_sta_col + 1);}}return false; } bool check (int _row, int _col) {int i = 0;for (; i < _col; i ++) {if (queen [i] == _row || ((queen [i] + i) == (_row + _col)) ||(queen [i] - i) == (_row - _col)) // stdlib.hreturn false;}return true;}int main (int argc, char* argv []) {int i = 0;if (argc >= 2) { if (! (_n = atoi (argv [1]))) {printf ("n must bigger than 0...\n"); // stdio.hreturn 0;}}queen = (int*) malloc (sizeof (int) * _n);memset (queen, 0, sizeof (int) * _n); // memory.hloop (0); printf ("n = %d, %d\n", _n, maxnum);return 0;}

编译环境:

Linux x86_64

gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3

gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04

0 0
原创粉丝点击