【C语言】使用递归解决八皇后问题

1、什么是八皇后问题

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

2、使用递归解决八皇后问题

        本次解决八皇后问题不使用回溯算法而使用递归实现。使用一个二维数组chess[8][8]表示棋盘,通过noDanger()函数判断皇后在指定棋盘的指定位置是否有危险。主要的思路如下:

(1)首先在第1行第1列放置第1个皇后(黑色方块表示皇后)。

                 【C语言】使用递归解决八皇后问题_第1张图片

(2)在第2行第1列放置第2个皇后,判断皇后在该棋盘是否危险。若危险,列数加一并继续判断是否危险;若不危险,那么在第3行第1列放置第3个皇后,并继续判断是否危险。若危险,列数加一并继续判断是否危险;若不危险,那么在第4行第1列放置第3个换后,并继续判断是否危险……假如某一行每一个位置都危险那么程序就会回到上一级函数,寻找上一行的其他安全点。

                【C语言】使用递归解决八皇后问题_第2张图片  【C语言】使用递归解决八皇后问题_第3张图片   【C语言】使用递归解决八皇后问题_第4张图片                 

        下图第七行全是危险点(红色方块表示危险点),所以会返回到递归函数的上一级,寻找新的安全点:

                【C语言】使用递归解决八皇后问题_第5张图片  

       但是由于第六行后面的点都危险,所以会再次返回递归函数的更上一级。通过多次递归调用总会寻找到8个皇后全部安全的棋盘布局。

               【C语言】使用递归解决八皇后问题_第6张图片

(3)当最后一个皇后放置成功后,打印棋盘

3、c语言代码

#include "stdio.h"
#include "string.h"

int count = 0;//计数总共可以得到多少种结结果

/*判断皇后在棋盘的某一个位置是否危险*/
//row : 皇后所在的行数
// j  : 皇后所在的列数
int noDanger(int row, int j, int chess[8][8])
{
	int count1 = 0;//计算一列中是否有多个皇后
	int count4 = 0;//计算一行中是否有多个皇后
	int count2 = 0;//计算主对角线是否有多个皇后
	int count3 = 0;//计算附对角线是否有多个皇后
	int i, k;
	chess[row][j] = 1;
	for (i = 0; i < 8; i++)//判断一行中有多少皇后
	{
		if (chess[i][j] == 1)
		{
			count4++;
		}	
	}
	for (i = 0; i < 8; i++)//判断一列中有多少皇后
	{
		if (chess[row][i] == 1)
		{
			count1++;
		}
	}
	/*判断主对角线*/
	for (i = j,k = row; 0<= i &&  0<=k; i--,k--)
	{
		if (chess[k][i] == 1)
		{
			count2++;
		}
	}
	for (i = j, k = row; 8> i && 8> k; i++, k++)
	{
		if (chess[k][i] == 1)
		{
			count2++;
		}
	}
	/*判断副对角线*/
	for(i = j, k = row; 0<= i && 8> k; i--, k++)
	{
		if (chess[k][i] == 1)
		{
			count3++;
		}
	}
	for (i = j, k = row; 8 > i&& 0<=k; i++, k--)
	{
		if (chess[k][i] == 1)
		{
			count3++;
		}
	}
	chess[row][j] = 0;
	if (count1 > 1 || count2 > 2 || count3 > 2 || count4 >1)//因为主对角线和副对角线多计算了一次,所以当他大于2才危险
	{ 
		return 0;
	}
	else
	{
		return 1;
	}
}
//满足题设的棋盘的打印
//row  : 表示第n行
//chess: 表示需要继续判断皇后是否危险的棋盘
void eightQueen(int row, int chess[8][8])
{
	int chessTemp[8][8];
	memset(&chessTemp, 0, sizeof(chessTemp));
	if (row == 8)//如果递归到了第8行,打印棋盘
	{
		printf("第%d种\n", ++count);
		for (int i = 0; i < 8; i++)
		{
			for (int j = 0; j < 8; j++)
			{
				printf("%d ",chess[i][j]);
			}
			printf("\n");
		}
	}
	else//如果没有递归到第8行
	{
		for (int j = 0; j < 8; j++)
		{
			if (noDanger(row, j, chess))//判断皇后在chess的第row行,j列处是否安全
			{
				chess[row][j] = 1;//把chess的安全点置1
				eightQueen(row + 1, chess);//到下一行寻找安全点
				chess[row][j] = 0;//将安全处的值清空判断该行下一列是否安全
			}
		}
	}
}

int main()
{
	int chess[8][8];
	memset(&chess, 0, sizeof(chess));
	eightQueen(0, chess);//打印所有满足结果的棋盘
	getc(stdin);//输入任意字符结束程序
	return 0;
}

4、结果如下,共92种棋盘布局满足题设:

【C语言】使用递归解决八皇后问题_第7张图片

高斯也有大意的时候

你可能感兴趣的:(C语言)