在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
结题思想:先给第一列的皇后一位置,根据规则,然后确定第二行皇后位置,以此类推,确定其余每列的皇后的位置。得出问题的解
给棋盘设置一个二维数组chess[8][8],全部初始化为0。找到每一列中合适的位置并赋为1,而确定列中元素的位置没有确定行中元素位置方便。可以转化为求解每行中这样的一个合适位置,找到则进行下一行的寻找,直到行数为8时递归结束获得问题的解。
定义两个函数EightQueen(row,n,chess)用于递归调用下一行的判断、safePosition(row,n,chess)用于需找安全的位置,即元素所在行、列及左右两条对角线上都不能有皇后存在。
代码如下:
#include <stdio.h>
int count;//全局变量记录有多少种
int safePositon(int row, int n, int (*chess)[8])
{
int i,j,flag1=0,flag2=0,flag3=0,flag4=0,flag5=0;
//判断列方向
for(i=0; i<8; i++)
{
if(*(*(chess+i)+n) !=0)
{
flag1=1;
break;
}
}
//判断左上方
for(i=row, j=n; i >= 0 && j >= 0; i--, j--)
{
if(*(*(chess+i)+j) !=0)
{
flag2=1;
break;
}
}
//判断右下方
for(i=row, j=n; i<8 && j<8; i++, j++)
{
if(*(*(chess+i)+j) !=0)
{
flag3=1;
break;
}
}
//判断右上方
for(i=row, j=n; i >=0 && j<8; i--, j++)
{
if(*(*(chess+i)+j) !=0)
{
flag4=1;
break;
}
}
//判断左下方
for(i=row, j=n; i<8 && j >= 0; i++, j--)
{
if(*(*(chess+i)+j) !=0)
{
flag5=1;
break;
}
}
if(flag1 || flag2 || flag3 || flag4 || flag5)
{
return 0;
}
else
{
return 1;
}
}
void EightQueen(int row, int n, int (*chess)[8])
{
//row表示行,j表示列,(*chess)[8]表示指向棋盘每一行的指针;一行一行的递归
int chess2[8][8],i,j;
for(i=0; i<n; i++)
{
for(j=0; j<n; j++)
{
chess2[i][j]=chess[i][j];
}
}
if(row == 8)//递归的结束条件
{
count++;
printf("第%d种\n",count);
for(i=0; i<8; i++)
{
for(j=0; j<8; j++)
{
printf("%d ",*(*(chess2+i)+j));
}
printf("\n");
}
}
else
{
for(j=0; j<8; j++)
{
if(safePositon(row, j, chess))
{
for(i=0; i<8; i++)
*(*(chess2+row)+i)=0;
*(*(chess2+row)+j)=1;
EightQueen(row+1, n, chess2);
}
}
}
}
int main(void)
{
int i,j,chess[8][8];
if(freopen("D:\\OUTPUT.txt","w",stdout)==NULL)
fprintf(stderr,"errorredirectingstdout\n");
for(i=0; i<8; i++)
{
for(j=0; j<8; j++)
{
chess[i][j]=0;//棋盘的初始化
}
}
EightQueen(0, 8, chess);
printf("一共有%d种 \n",count);
fclose(stdout);
}
由于生成结果多,控制台的缓存不足以显示所有结果。在这里用freopen("D:\\OUTPUT.txt","w",stdout)==NULL将stdout重定向到文件中保存。若要重新将输出重定向到控制台,可以调用stream=freopen("CON","w",stdout);(stream是一个文件指针)