八皇后问题,八皇后是由数学家高斯提出的一个关于国际象棋的数学问题,要求一个8x8的正方形棋盘上,8个皇后棋子放在棋盘上且不能被互相攻击到,皇后的棋力十分强大,它可以直接覆盖米字形的杀伤范围,具体可以参考象棋中的車,它是十字形杀伤范围。
那么按照我们男同胞的思维,大部分男同胞肯定都很羡慕古代皇帝的生活,3000佳丽,那么这个问题我们把它类比为一个你的8个老婆不能碰面的问题,因为碰面大概率就会掐起来,于是我们就假设你要在64块正方形空地盖8座宫殿,你的8个老婆分别只能住一座,修路的时候只能修米字形的路,那么怎么样盖房子才不会使她们通过修的路相遇?
这个问题高斯穷其一生也才解出了76种解法的问题,后面的数学家用图论证明了共有92种解法。我们现在站在了巨人肩膀上,并且有了计算机这种利器,那么我们就可以通过简单的编程去求解它,而且轻轻松松可以求出92种解法。它本来是一个回溯算法的经典问题,但我们今天要用的是更好理解的递归法去求解。
我们先来理清一下思路,递归法的核心要义在于抽象问题,把复杂问题简单化,那么我们怎么样去简化这个问题,我们可以先从第一行第一个位置试起,然后求下面的每行的解,因为要使不能相遇,那肯定一行只允许一个皇后存在,也就是说我们从第一行第一个开始通过不断的将棋盘的每个位置作为试点,肯定能得出全部解。既然是棋盘我们就可以借助二维数组进行存储。
那么我们就来贴代码实现
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int count = 0;
//判断当前棋子所在位置是否安全的函数
int notdange(int row,int rank, int(*chess)[8])
{
int flag = 1,i,j;
//判断列
for (i = 0; i < 8; i++)
{
if (*(*(chess + i) + rank )!= 0)
{
flag = 0;
break;
}
}
//判断左上
for (i = row, j = rank; i >= 0&&j>=0; i--,j--)
{
if (*(*(chess + i) + j) != 0)
{
flag = 0;
break;
}
}
//判断右下
for (i = row, j = rank; i < 8 && j <8; i++, j++)
{
if (*(*(chess + i) + j) != 0)
{
flag = 0;
break;
}
}
//判断右上
for (i = row, j = rank; i >= 0 && j < 8; i--, j++)
{
if (*(*(chess + i) + j) != 0)
{
flag = 0;
break;
}
}
//判断左下
for (i = row, j = rank; i <8 && j >= 0; i++, j--)
{
if (*(*(chess + i) +j) != 0)
{
flag = 0;
break;
}
}
return flag;
}
//主要的八皇后递归算法
void EithtQueen(int row,int rank,int (*chess)[8])
{
int chess2[8][8];//临时棋盘,用作打印
for (int i = 0; i < 8; i++)//初始化
{
for (int j = 0; j < 8; j++)
{
chess2[i][j] =chess[i][j];
}
}
//第八行元素确定后打印输出
if (8 == row)
{
printf("第 %d 种\n", count + 1);
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
printf("%d ",*(*(chess2+i)+j)) ;
}
printf("\n");
}
printf("\n");
count++;
}
else
{
//主要实现棋盘从1-1到8-8每个位置开始的函数
for (int j = 0; j < rank; j++)
{
if ( notdange(row,j,chess) )
{
for (int i = 0; i < 8; i++)
{
*(*(chess2 + row) + i)=0;
}
*(*(chess2 + row) + j) = 1;
EithtQueen(row + 1, rank, chess2);//每一列检查算作一次循环结束,知道j列第8行才会被输出一次
}
}
}
}
int main()
{
int chess[8][8];
memset(chess,0,sizeof(chess));
EithtQueen(0, 8, chess);
printf("共有 %d 种方法", count);
return 0;
}