八皇后问题:
在国际象棋中,皇后可以在没有限定一步走几格的前提下,对棋盘中的其他棋子进行直向吃、横向吃以及对角线方向吃,皇后在放入之前必须考虑所放位置的直线方向、横向方向以及对角线方向是否已经放置了皇后
在8*8棋盘上称其为八皇后问题,在N*N棋盘上就称其为N皇后问题
算法分析:
八皇后问题就是利用堆栈结构以及回溯算法的策略
在每一次放入皇后之前,都要判断所放位置的直线方向、横向方向以及对角线方向是否已经放置了皇后,如果没有放置,放皇后,然后将此皇后放入栈中(Q[++top]);反之,走下一列(二维数组存储)
如果到棋盘的 i 行放皇后,直到 j (代表列)等于7时,还没有找到合适的位置放皇后,则返回到上一行,i--,将 j 置零,重新找位置放皇后 (此乃回溯算法)
如果top(栈的大小为8)等于7,说明最后一行皇后放置完毕,完成了一组解,然后输出此组解
代码实现:
非递归:一组解
#include<stdio.h>
#include<stdlib.h>
//输出
void pint(int a[8][8]){
for(int i=0;i<8;i++) {
for(int j=0;j<8;j++)
printf("%d",a[i][j]);
printf("\n");
}
}
void pint1(int Q[8]){
printf("行号: ");
for(int i=0;i<8;i++){
printf("%d ",i);
}
printf("\n");
printf("皇后的列号 ");
for(int i=0;i<8;i++){
printf("%d ",Q[i]);
}
}
void sortKing(int a[8][8]){
int i,j,top;
//存放皇后
int left[15]={},right[15]={},cal[8]={};//左斜线,右斜线,放有皇后的列号
int Q[8];//存放每一行皇后的列号
top=-1;
i=0,j=0;
while(i<8){
while(top!=7){
for( ;j<8;j++){
if(!cal[j]&&!left[i+j]&&!right[7+i-j]){//判断对角线和列放皇后
a[i][j]=1;
Q[++top]=j;
left[i+j]=1;
right[7+i-j]=1;
cal[j]=1;
i++;
j=0;
break;
}
}
//i行不能放,回溯
if(j==8){
i--;
j=Q[top--];//出栈
a[i][j]=0;
cal[j]=0; //列
left[i+j]=0;
right[7+i-j]=0;
j++;
}
}
}
pint1(Q);
printf("\n输出8*8数组\n");
pint(a);
}
int main(void){
int a[8][8];
for(int i=0;i<8;i++)
for(int j=0;j<8;j++)
a[i][j]=0;
sortKing(a);
}
递归:多组解
#include<stdio.h>
#define N 8
int cnt=0;
int col[N]={0},left[2*N-1]={0},right[2*N-1]={0};
int Q[N]={0};
/*
函数作用:打印出当前的皇后的所在的位置
函数参数:皇后数组的首地址Q,当前是第几组解cnt
无返回值
*/
void PrintQueen(){
int i,k;
printf("第%d组解\n",++cnt);
for(i=0;i<N;++i){
for(k=0;k<N;++k){
if(Q[i]==k)
printf("Q ");
else
printf("* ");
}
printf("\n\n");
}
}
/*函数作用:找出所有的皇后位置并输出打印
函数参数:第i行数
无返回值
*/
void Queen(int i){
int j;
for(j=0;j<N;++j){
if((!col[j])&&(!left[i+j])&&(!right[i+N-1-j])){
Q[i]=j;
right[i+N-1-j]=1;
left[i+j]=1;
col[j]=1;
if(i<N-1){
Queen(i+1); //下一行找皇后
}
else{
PrintQueen(); //格满,输出
}
//返回抹掉皇后,继续放
right[i+N-1-j]=0;
left[i+j]=0;
col[j]=0;
}
}
}
int main(void){
//找出所有的皇后位置并输出打印
Queen(0);
return 0;
}