八皇后问题是一个叫马克思的西洋棋手1848年提出来的,后来伟大的数学家高斯先生历尽千辛万苦算出了76种,当时计算机还没有诞生所以即便是公认的数学大师高斯也无法准确的计算的出来,其正确结果是92种。八皇后问题是学习数据结构里很经典的一个问题,在8*8的棋盘里,大家都知道皇后是横、纵、斜均可以移动,而且距离不限。摆放8个皇后,使其两两之间不会形成威胁,如何摆放?
这张图面是找度娘要的,即便还是不理解的人根据这张图也能知道问题的架构了:
计算目的:
1、遍历并输出每一种结果;
2、求得有多少种解法。
利用回溯算法计算把皇后问题是比较简单的! 我利用递归,就是为了求解!就是为了更深刻的了解递归!
进入代码,我会将代码做详细的注释,方便需要的同学去学习:
由main开始:
#include <stdio.h>
#include <stdlib.h>
#define N 8 /*数组的范围,表示8*8的棋盘*/
int count=0; /*用于统计有多少种算法,固用全局变量*/
int main(void)
{
int chess[N][N];
for (int i=0;i<N;i++) /*初始化棋盘,0代表空,1代表放皇后*/
{
for (int j=0;j<N;j++)
{
chess[i][j]=0;
}
}
Queen(0,N,chess); /*进入递归*/
system("pause");
return 0;
}
递归的函数实现如下:
第一个参数要搞清楚,是从第几行开始,而不是总共有几行
void Queen(int row,int col, int (*chess)[8])
{
int tempChess[N][N],i,j; /*创建临时棋盘用于输出*/
for (i=0;i<N;i++)
{
for (j=0;j<N;j++)
{
tempChess[i][j]=chess[i][j]; /*初始化临时棋盘*/
}
}
if(8==row) /*递归结束条件,当考察到第8行结束,递归就结束了*/
{
printf("第 %d 种情况.\n",count++); /*输出棋盘,并count++*/
for (i=0;i<N;i++)
{
for (j=0;j<N;j++)
{
printf("%d ",tempChess[i][j]);
}
printf("\n");
}
printf("\n\n");
}
else
{ /*核心递归区*/
for (j=0;j<col;i++)
{
if (NotDanger(row,j,tempChess)) /*利用一个函数判断该位置是否安全,如果安全进入递归条件*/
{
for (i=0;i<N;i++)
{
tempChess[row][i]=0; /*首先将该列全部填充0*/
}
chess2[row][j]=1; /*在对应位置摆放皇后*/
Queen(row+1,col,tempChess); /*递归调用,这里row++而已。*/
}
}
}
}
写好了,其实就这么简单,寥寥数行而已。但初学者理解起来会比较困难。当然不要忘了实现NotDanger方法:
int NotDanger(int row,int col,int (*chess)[N])
{
for (int i=row-1;i>=0;i--)
{
if(chess[i][col]==1)
{
return 0;
}
}
for (int i=row+1;i<N;i++)
{
if(chess[i][col]==1)
{
return 0;
}
}
for(int i=row-1,j=col-1;i>=0&&j>=0;i--,j--)
{
if(chess[i][j]==1)
{
return 0;
}
}
for (int i=row+1,j=col+1;i<N && j<N;i++,j++)
{
if(chess[i][j]==1)
{
return 0;
}
}
for (int i=row-1,j=col+1;i>=0 && j<N;i--,j++)
{
if(chess[i][j]==1)
{
return 0;
}
}
for (int i=row+1,j=col-1;i<N&&j>=0;i++,j--)
{
if(chess[i][j]==1)
{
return 0;
}
}
return 1;
}
看输出结果:
其实有好多的,如果用文件输出的才能全部输出出来!
好啦,结束了!!!我真的觉得八皇后问题不是一个简单的问题,特别对于我。为了看懂这个算法我也用了不少的时间才看懂!!!数据结构就是这样,要锲而不舍!
加油!!!