题目
八皇后问题,在 8×8 的国际象棋棋盘上摆放8个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法,并打印每一种摆法。
解题思路
判断方法:
从上向下依次每行摆放一个皇后,这样就不需要判断一行中是否会不止一个皇后。
在摆放时判断一个位置是否可以摆放皇后:
1.黄色线上只能有一个皇后;对于黄色线上的任意两个方格坐标 (i, j) 、(row, col) 满足 row - i = col -j 。
2.蓝色线上只能有一个皇后;对于蓝色线上则是 row + col = i + j 。
3.同一列只能有一个。
摆放过程:
在添加过程中,每一行都从左向右摆放,当冲突时就摆下一列,如果不冲突就在这个位置摆上皇后,然后去摆下一行;如果这一列摆完也没有找到不冲突的位置,就回退到上一行,将皇后向右移一列。
不断循环上述过程,当最后一行也摆放上皇后之后,这时候就找到一种摆法了。
代码实现:
使用二维数组
#include <stdio.h>
//判断位置row、col是否可以放下皇后
int judge(int queens[][8], int row, int col)
{
for(int i=0; i<row; i++)
{//在摆放row,col位置时,0~row-1行已经摆放过
for(int j=0; j<8; j++)
{// 二维数组元素为1表示已经摆放了皇后
if(row-i == col-j && 1 == queens[i][j])
{//黄色斜线
return 0;
}
if(row+col == i+j && 1 == queens[i][j])
{//蓝色斜线
return 0;
}
}
if(1 == queens[i][col])
{//同一列只能摆放一个
return 0;
}
}
return 1;
}
int judge1(int queens[][8], int row, int col)
{
for(int i=1; row-i >= 0 && col-i >= 0; i++)
{//黄色斜线
if(1 == queens[row-i][col-i])
{
return 0;
}
}
for(int i=1; row-i>=0 && col+i<8;i++)
{//蓝色斜线
if(1 == queens[row-i][col+i])
{
return 0;
}
}
for(int i=0; i<row; i++)
{//同一列
if(1 == queens[i][col])
{
return 0;
}
}
return 1;
}
//打印摆放方法
void showqueens(int queens[][8], int n)
{
printf("------------------------\n");
for(int i=0; i<8; i++)
{
for(int j=0; j<8; j++)
{
printf("%d ", queens[i][j]);
}
printf("\n");
}
printf("------------------------\n");
}
//打印所有摆放方法,并返回方法个数
int putqueens(int queens[][8], int n)
{
int i=0, j=0;//当前需要摆放的位置
int cnt=0;//方法个数
while(1)
{
if(judge(queens, i, j))
{//(i, j)可以摆放
queens[i][j] = 1;//1表示已经摆放了
i++;//摆放下一行
j=0;//摆放下一行时从第一列开始摆放
}
else
{//(i, j)不可以摆放
j++;//摆放下一列
}
while(8 == j)
{//当i行没有一个位置能够摆放时
i--;//去i-1行
for(int m=0; m<8; m++)
{
if(1 == queens[i][m])
{
queens[i][m] = 0;//0表示没有摆放皇后
j = m+1;//将i-1行的皇后像后移一位
}
}
}
if(8 == i)
{//如果已经摆放了8个皇后
showqueens(queens, 8);//打印摆法
cnt++;//摆法方法+1
do{
i--;//去i-1行找下一种的摆法
for(int m=0; m<8; m++)
{
if(1 == queens[i][m])
{
queens[i][m] = 0;
j = m+1;
}
}
}while(8 == j);
}
if(-1 == i)
{//所有方法都找到时
return cnt;
}
}
}
int main()
{
int q[8][8]={};
int m = putqueens(q, 8);
printf("%d\n", m);
return 0;
}
一维数组
这里用一个长度为 8 的一维数组实现,数组元素值的范围是0~7,对应二维数组的列,queens[row] = col 表示(row, col) 这个位置有一个皇后。
#include <stdio.h>
int judge(int queens[], int row, int col)
{
for(int i=0; i<row; i++)
{
if(col == queens[i] || row-i == col-queens[i] || row+col == i+queens[i])
{
return 0;
}
}
return 1;
}
int show(int queens[], int n)
{
for(int i=0; i<n; i++)
{
printf("%d ", queens[i]);
}
printf("\n");
}
int putqueens(int queens[], int n)
{
int i=0, j=0;
int cnt=0;
while(1)
{
if(judge(queens, i, j))
{
queens[i] = j;
i++;
j=0;
if(i == n)
{
show(queens,8);
cnt++;
do{
i--;
j = queens[i] + 1;//j可能超过最大值
}while(j == n);
}
}
else
{
j++;
while(j == n)
{
i--;
j = queens[i] + 1;
}
}
if(-1 == i)
{
return cnt;
}
}
}
int main()
{
int q[8] = {};
int n = putqueens(q, 8);
printf("%d\n", n);
return 0;
}
结果总共有92种。