八皇后问题学习笔记

 1.       问题描述:

n×n的棋盘上放置n个不能互相捕捉的国际象棋“皇后”的所有布局。这是来源于国际象棋中的一个问题。皇后是棋盘上最具杀伤力的一个棋子,她可以捕捉与她在同一行,或同一列,或同一斜线(有两条)上的所有棋子。如下图所示,红线经过的格子都会被皇后捕捉。

 

 

2.       问题分析:

1)    皇后的杀伤力在她所对应的行,列,和两条斜线上,所以应该满足该皇后所在的行、列和两条斜线都不存在其它皇后。

2)    所以为了避免皇后冲突,一个可行的办法是将棋盘上所有的行,列,和斜线的占用状态分别用数组存起来,初始状态为未占用。在每成功放入一个皇后以后,将该皇后所对应的行,列,和两条斜线的状态更新为占用。在每次尝试将某个皇后放置到某个位置的时候,需要检查该位置所对应的行,列,和斜线的占用状态,只有全部未被占用,才可以将该皇后放到该位置。

3)    接下来的问题有两个:一是如何用数组来存储棋盘上所有的行,列,和斜线的占用状态?二是对棋盘上每一个位置如何找到它所对应的行、列和斜线在状态数组中的位置。以下分行、列、左低右高斜线和左高右低斜线四种情况来讨论:

4)    行:对n×n的棋盘有n行(1 n),用一个n + 1维的数组row[n + 1]row[0]不用)来表示每一行的占用状态。位置(ij)对应的行的占用状态为row[i]

5)    列:对n×n的棋盘有n列(1 n),用一个n + 1维的数组col[n + 1]col[0]不用)来表示每一列的占用状态。位置(ij)对应的列的占用状态为col[j]

6)    左低右高斜线:n×n的棋盘总共有2n – 1条左低右高斜线,所以可以用2n维的数组b[2n]b[0]不用)来存储每一条左低右高斜线的占用状态。。对某一条斜线,其特点是它所经过的每一个格子的(列号 + 行号)相等,所以可以用这个值作为数组下标来唯一标记每一条左低右高斜线,为了使下标从1开始,对所有的下标减1。如下图所示。位置(ij)对应的左低右高斜线的占用状态为b[i + j – 1]

 

7)    左高右低斜线:n×n的棋盘总共有2n – 1条左高右低斜线,所以可以用2n维的数组c[2n]c[0]不用)来存储每一条左高右低斜线的占用状态。。对某一条斜线,其特点是它所经过的每一个格子的(列号 行号)相等,所以可以用这个值作为数组下标来唯一标记每一条左高右低斜线,为了避免出现负值,将所有的下标值都加上一个n。如下图所示。位置(ij)对应的左高右低斜线的占用状态为c[n + j - i]

  

3.       解题思路:

1)    要将n个皇后放到n×n的棋盘中,则每一列必须且只能放一个皇后。所以问题转化为确定皇后在每一列中的位置(在第几行上)。

2)    从第一列开始,依次考察每一列。

3)    在考察每一列的时候,总是从第一行开始,尝试将皇后放入,如果可以放入,就接着考察下一列的第一行。如果不可以放入,就接着考察这一列的下一行,直到成功,然后接着考察下一列的第一行。

4)    如果这一列的每一行都不可以放入,说明这一列前面各列的皇后放置有问题,导致这一列无法放入,需要回溯。

5)    回溯的时候,如果前面的一列每一行都已经被尝试过了,就需要接着往前回溯,直到找到还有行未被尝试过的列,然后尝试这一列的下一行。

6)    在回溯过程中经过的每一列都需要将已经放入的皇后取出来,以备后面重新选择位置放入。

7)    如果每一列都被考察完毕,即每一列中的皇后都找到了合适的位置,则找到一个解。

8)    在找到一个解后,如果还要寻找其它解,则需要回溯,尝试其它情况。

9)    当回溯到第0列时,说明1 ~ n列的所有行都已经被尝试过了,没有其它情况可以尝试,结束程序。

  

4.       代码:

Code

 

posted on 2008-10-27 01:05  spacer_robot  阅读(1559)  评论(4编辑  收藏  举报

导航