八皇后问题(回溯算法)

        八皇后问题是古老的问题,十八世纪由一个国际象棋手提出的,即在一个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 : yez
	date : 2015/5/17
	describe : eight queen algorithm
*/
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <stdbool.h>

// default value
int _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.h
			return 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.h
			return 0;
		}
	}

	queen = (int*) malloc (sizeof (int) * _n);
	memset (queen, 0, sizeof (int) * _n); // memory.h

	loop (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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值