#include <stdio.h>
#include <stdlib.h>
void* queens(int c[8],int chess[8][8]); //八皇后回溯算法
int reasonalbe(int chess[8][8]); //用于判断棋子是否合法
void printchess(int chess[8][8],int c[8]); //输出棋盘阵列
void putchess(int chess[8][8],int c[8]); //放置皇后
void print_c(int c[8]); //输出一维数组,显示每行皇后的位置
int main()
{
int i,j; //i为行,j为列
int c[8]={0,0,0,0,0,0,0,0}; //存储每行皇后的位置
int chess[8][8]; //棋盘数据结构
for(i = 0;i < 8;i++) //棋盘数据初始化
for(j = 0;j < 8;j++)
chess[i][j] = 0;
printchess(chess,c); //显示初始化之后的结果
queens(c,chess); //执行八皇后算法
return 0;
}
void* queens(int c[8],int chess[8][8])
{
int k = 0;
int flag = 0;
while(k >= 0 && flag == 0)
{
while(c[k] <= 8 && flag == 0)
{
printf("每行的皇后位置如下表:");
c[k] = c[k] + 1;
print_c(c); //输出每行皇后的位置
putchess(chess,c); //放置皇后
printchess(chess,c); //输出棋盘当前皇后情况
//printf("status is %d\n\n",reasonalbe(chess));
/*开始分类讨论*/
if(reasonalbe(chess) == 0 && k == 7) //1、八皇后问题解决
{
printf("八皇后问题得到深度优先解\n\n");
printf("解向量为:");
print_c(c);
printf("\n");
flag = 1; //问题解决,直接退出算法
break;
}
else if(reasonalbe(chess) == 0 && k < 7) //2、得到部分解
{
printf("这是部分解,继续\n\n");
k = k + 1;
break;
}
else if(reasonalbe(chess) == 1 && c[k] < 7) //3、新放的皇后和已有的冲突
{
printf("碰到冲突,尝试同行下一个\n\n");
continue;
}
else if(reasonalbe(chess) == 1 && c[k] == 7) //4、一行皇后试到底,无路可走
{
printf("开始回溯\n\n");
c[k] = 0;
k = k - 1;
continue;
}
else if(c[k] > 8) //5、回溯后如果再碰到回溯
{
printf("开始多重回溯\n\n");
c[k] = 0;
k = k - 1;
continue;
}
}
}
if(flag == 1) //6、如果问题解决,输出皇后棋盘
printchess(chess,c);
else
printf("no solution!\n\n");
}
int reasonalbe(int chess[8][8]) //判断是否可以放皇后
{
int flag = 0;
int number = 0;
int i,j,k;
for(i = 0;i < 8;i++) //行扫描,判断每一行是否有两个皇后
{
for(j = 0;j < 8;j++)
{
if(chess[i][j] == 1) //如果有皇后,计数器number+1
{
number ++;
//printf("%d,%d\n",i,j);
}
}
if(number > 1) //如果每行多于一个皇后
{
flag = 1; //标志位设置为1,退出判断
i = 8;
break;
}
number = 0; //计数器归0,进行下一行判断
}
for(i = 0;i < 8;i++) //列扫描,判断每一列是否有两个皇后
{
for(j = 0;j < 8;j++)
{
if(chess[j][i] == 1) //如果一列上有皇后,计数器+1
{
number ++;
//printf("%d,%d\n",j,i);
}
}
if(number > 1) //原理和行类似,不再阐述
{
flag = 1;
i = 8;
break;
}
number = 0;
}
for(i = 7;i >= 0;i--) //斜扫描1,扫描区域为主对角线以下的每一个斜列
{
for(j = 0;i + j <= 7;j++)
{
if(chess[i + j][0 + j] == 1)
{
number ++;
//printf("%d,%d\n",i+j,j);
}
}
if(number > 1) //原理和之前行列类似
{
flag = 1;
i = 8;
break;
}
number = 0;
}
for(k = 0;k <= 7;k ++) //斜扫描2,扫描区域为副对角线下方区域
{
for(i = 7 - k,j = 7; i <= 7; i++,j--)
{
if(chess[i][j] == 1)
{
number ++;
}
}
if(number > 1)
{
flag = 1;
i = 8;
break;
}
number = 0;
}
for(k = 0;k <= 7;k++) //斜扫描3,扫描区域为主对角线上方区域
{
for(i = 0,j = 7 - k;j <= 7;i++,j++)
{
if(chess[i][j] == 1)
{
number++;
}
}
if(number > 1)
{
flag = 1;
i = 8;
break;
}
number = 0;
}
for(k = 0;k <= 7;k++) //斜扫描4,扫描区域为副对角线上方区域
{
for(i = 0,j = k;j >= 0;i++,j--)
{
if(chess[i][j] == 1)
{
number++;
}
}
if(number > 1)
{
flag = 1;
i = 8;
break;
}
number = 0;
}
return flag;
}
void printchess(int chess[8][8],int c[8])
{
int i,j;
printf("当前的棋盘的情况如下所示:\n\n");
for(i = 0;i <= 7;i ++)
{
for(j = 0;j <= 7;j ++)
{
if(chess[i][j] == 1)
printf("■");
else
printf("□");
}
printf("\n");
}
printf("\n");
}
void putchess(int chess[8][8],int c[8])
{
int i,j;
for(i = 0;i < 8;i++) //放置棋子前,先全部初始化
for(j = 0;j < 8;j++)
chess[i][j] = 0;
for(i = 0;i < 8;i ++) //根据解向量进行放棋子
{
if(c[i] != 0)
chess[i][c[i] - 1] = 1;
}
printf("\n");
}
void print_c(int c[8])
{
for(int i=0;i<8;i++)
printf("%d ",c[i]);
printf("\n");
}