使用比特位图解决八皇后问题

来源:互联网 发布:剑三脸型数据怎么导出 编辑:程序博客网 时间:2024/04/30 14:21

八皇后问题,是一个古老而著名的问题,是回溯算法的典型例题。该问题是十九世纪著名的数学家高斯1850年提出:在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。计算机发明后,有多种方法可以解决此问题。(百度百科)

百度百科提到了两种解法:残卷法和深搜,这两种方式相信大家都可以想到。“残卷法”是确定每一步之后将剩余棋盘不可用的位置都标记出来,代码实现比较繁琐;而提到的深搜的方法需要保存额外的信息,也比较麻烦。

这里,我们注意到:8X8棋盘,8皇后,而8正好是一个字节的比特数!利用C语言的位操作可以轻松的实现对此问题条件限制的判断。OK,我们继续分析这个问题,任意两个皇后不能处于同一行、同一列或同一斜线上,那么有条件限制:
a) 每一行只有一个皇后,这样我们每一步可以确定一个皇后的位置,共8步
b) 每一列只有一个皇后,我们可以将已确定的皇后列位置标记出来(按位或),新增的皇后不能处于这些位置
c) 两皇后不能位于同一斜线如何判断?思考如果两皇后在同一斜线,那么固定一个皇后的列位置,将另一个皇后的列位置左移(或右移)两个皇后的行间距,则两皇后位置重合。

有了如上三种条件限制,同样采用深搜的思路,代码就非常容易了。

#include <stdio.h>#define QUEEN_MAX8unsigned char chess_board[QUEEN_MAX];static int solutions = 0;void Queen8(int step){int i, j;unsigned char position;if(step == QUEEN_MAX-1)/* 最后一步 */{position = 0;for(i=0; i<QUEEN_MAX-1; i++)position |= chess_board[i];position = ~position;/* 确定最后一个皇后的列位置 */for(i=0; i<QUEEN_MAX-1; i++){/* 最后一个皇后不能和其它在同一斜线 */if((position == chess_board[i]>>(step-i)) ||(position == chess_board[i]<<(step-i))){return;}}solutions++;/* 解法+1 */}else{for(j=0; j<QUEEN_MAX; j++){/* 每行都有8个位置 */position = 0x1<<j;for(i=0; i<step; i++){/* 当前皇后不能和其它在同一列和同一斜线 */if(((position & chess_board[i]) != 0) ||(position == chess_board[i]>>(step-i)) ||(position == chess_board[i]<<(step-i)))break;}if(i == step){/* 进行下一步 */chess_board[i] = position;Queen8(step+1);}}}return;}int main(){Queen8(0);printf("%d\n", solutions);return 0;}