任务
国际西洋棋棋手马克斯·贝瑟尔于1848年提出在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。请设计算法编写程序解决。
分析
从第一行开始,当某一行皇后位置不与前面所有皇后位置冲突,那么记录该行皇后位置并调用递归函数进入下一行,摆放下一个皇后,逐个位置摆放,若该行所有位置都被其他皇后占领,那么就回溯到上一行重新摆放上一行皇后,直至所有皇后都不冲突。那么记录一次方法然后回溯寻找其他摆放方法。(回溯与递归算法)
流程图
存储结构设计
int place[8]={0}; /*皇后位置*/
bool flag[8]={1,1,1,1,1,1,1,1}; /*定义列*/
/*共有15个对角线,因此定义一个长度为15的bool型数组,
初值为1代表该对角线没有被皇后占领,若被皇后占领则赋值为0*/
bool d1[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; /*定义上对角线*/
bool d2[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ; /*定义下对角线*/
int number=0; /*记录解的个数*/
源代码
/*八皇后问题:求解并输出八皇后的所有解(92个解)*/
#include<stdio.h>
typedef int bool;
#define false 0
#define true 1
int place[8]={0}; /*皇后位置*/
bool flag[8]={1,1,1,1,1,1,1,1}; /*定义列*/
/*共有15个对角线,因此定义一个长度为15的bool型数组,
初值为1代表该对角线没有被皇后占领,若被皇后占领则赋值为0*/
bool d1[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; /*定义上对角线*/
bool d2[15]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} ; /*定义下对角线*/
int number=0; /*记录解的个数*/
/*定义输出函数*/
void print(){
int col, i, j;
number++; /*每调用一次输出函数number自加一次,记录解的个数*/
printf("No.%2d\n", number);
int table[8][8]={0}; /*设置一个8*8的棋盘*/
for (i=0;i<8;i++)
table[i][place[i]]=1; /*将每一行皇后所在位置赋值为1*/
for (i=0;i<8;i++){
for (j=0;j<8;j++)
printf("%d|",table[i][j]);
printf("\n");
}
}
/*定义递归回溯函数*/
int queen(int n){
int col;
for (col = 0; col < 8; col++){
if (flag[col] && d1[n-col+7] && d2[n+col]){ /*判断皇后是否冲突*/
place[n] = col; /*放置皇后*/
/*将该皇后所在的行、列、对角线设置为被占领*/
flag[col] = false;
d1[n-col+7] = false;
d2[n+col] = false;
if(n<7)
queen(n+1); /*当行数小于7时;递归调用下一行*/
else
print(); /*调用输出函数*/
flag[col]=true; /*回溯*/
d1[n-col+7]=true;
d2[n+col]=true;
}
}
return number;
}
int main()
{
number = queen(0); /*从第0行开始执行*/
printf("共有%d种摆放方法", number);
return 0;
}