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

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

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

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

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

#include <stdio.h>

#define QUEEN_MAX	8

unsigned 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;
}

 

你可能感兴趣的:(c,算法,百度,语言)