八皇后问题由高斯(C. F. Gauss)最早在1850年提出并研究,但并未完全解决。N皇后问题指在一个N×N的棋盘上放置N个皇后,使任意两个皇后都不能互相攻击。按国际象棋规则,两个皇后,若在同一行上,或在同一列上, 或在同一条斜线上, 则她们可以互相攻击。下图即满足八皇后条件的一种棋局。
编写程序给出所有摆法和满足条件的棋局数目。
代码思路:
1.找出对角线(包括主,副对角线)之间的规律关系。
2.了解 回溯法的使用(递归)如果你不会,那么看完博客你大概也就懂了。
八皇后问题是使用回溯法解决的典型案例。算法的解决思路是:
1. 从棋盘的第一行开始,从第一个位置开始,依次判断当前位置是否能够放置皇后,判断的依据为:同该行之前的所有行中皇后的所在位置进行比较,如果在同一列,或者在同一条斜线上(斜线有两条,为正方形的两个对角线),都不符合要求,继续检验后序的位置。
2. 如果该行所有位置都不符合要求,则回溯到前一行,改变皇后的位置,继续试探。
3. 如果试探到最后一行,所有皇后摆放完毕,则直接打印出 8*8 的棋盘。最后一定要记得将棋盘恢复原样,避免影响下一次摆放。
代码如下(看着多,其实大部分是注释占行,其实很简洁明了):
#include <stdio.h>
int Queenes[8]={0},Counts=0;//queen是一个列坐标;
int Check(int line,int list){
//遍历该行之前的所有行
for (int index=0; index<line; index++) {
//挨个取出前面行中皇后所在位置的列坐标
int data=Queenes[index];
//如果在同一列,该位置不能放
if (list==data) {
return 0;
}
//如果当前位置的斜上方有皇后,在一条斜线上,也不行
if ((index+data)==(line+list)) {
return 0;
}
//如果当前位置的斜下方有皇后,在一条斜线上,也不行
if ((index-data)==(line-list)) {
return 0;
}
}
//如果以上情况都不是,当前位置就可以放皇后
return 1;
}
//输出语句
void print()
{
for (int line = 0; line < 8; line++)
{
int list;
for (list = 0; list < Queenes[line]; list++)
printf("0");
printf("#");
for (list = Queenes[line] + 1; list < 8; list++){
printf("0");
}
printf("\n");
}
printf("================\n");
}
void eight_queen(int line){
//在数组中为0-7列
for (int list=0; list<8; list++) {
//对于固定的行列,检查是否和之前的皇后位置冲突
if (Check(line, list)) {
//不冲突,以行为下标的数组位置记录列数
Queenes[line]=list;
//如果最后一样也不冲突,证明为一个正确的摆法
if (line==7) {
//统计摆法的Counts加1
Counts++;
//输出这个摆法
print();//因为是void型函数
//每次成功,都要将数组重归为0
Queenes[line]=0;
return;
}
//继续判断下一样皇后的摆法,递归
eight_queen(line+1);
//不管成功失败,该位置都要重新归0,以便重复使用。找该种的其他写法。
Queenes[line]=0;//会开始找下一个坐标是,因为还在for循环里面,所以还是line里面。
//如果真的不行,那就会在跳一次eight再来for,总可以出现。每一层的for就是在遍历
//所有情况了。像是树的第一层,所谓回溯算法就是递归而已,递归!!!
}
}
}
int main() {
//调用回溯函数,参数0表示从棋盘的第一行开始判断,(int)型嘛
eight_queen(0);
printf("摆放的方式有%d种",Counts);
return 0;
}