1.“八皇后”问题
八皇后问题是十九世纪著名数学家高斯于1850年提出的。问题是:在8*8的棋盘上摆放8个皇后,使其不能互相攻击,即任意的两个皇后不能处在同一行,同一列,或同一斜线上。可以把八皇后问题拓展为n皇后问题,即在n*n的棋盘上摆放n个皇后,使其任意两个皇后都不能处于同一行、同一列或同一斜线上。
2.冲突条件判断
如下图,方块内的值(i,j)表示第i行第j列。(1,1)位置如果放了皇后,那么(1,1)位置所在的行,列,斜线上都不能再放皇后。

如何判断两个位置冲突呢?
(1)判断两个位置是否再斜线上:根据斜率
A(1,1)位置,B(2,0)位置和C(2,2)位置,A和B冲突:(0-1)/(2-1)==-1,A和C冲突:(2-1)/(2-1)==1。
因此,对于任意两点A(x1,y1)和B(x2,y2),两点斜线冲突满足条件:abs((y2-y1)/(x2-x1))==1,
该公式转换为:abs(y2-y1)== abs(x2-x1)
(2)判断两个位置是否在同一列/同一行
任意两点A(x1,y1)和B(x2,y2)在同一列满足条件:y1 == y2,在同一行满足条件:x1 == x2
判断冲突代码如下:
int valid(int row, int col) //判断第row行第col列是否可以放置皇后
{
int i;
for (i = 0; i < QUEEN; ++i) //对已得到的解搜索,看是否冲突
{ //判断列冲突与斜线上的冲突
//表示第i行第col列放了皇后,(row - i) / (col - arr[i]) != 1 或 -1
// arr[i] = k表示第i行第k列放了皇后
if (a[i] == col || abs(i - row) == abs(a[i] - col))
return 0;
}
return 1;
}
3.进入正题--回溯法解决
(1)初始化棋盘
#define INITIAL -10000 //棋盘的初始值const int QUEEN = 8;int a[QUEEN];//表示解空间a[1]=2表示[1,2]位置有皇后
void init()//初始化
{
int *p;
for(p=a;p<a+QUEEN;++p)
*p = INITIAL;
}
(2)非递归回溯
void queen() //N皇后程序
{
int n = 0;
int i = 0, j = 0;//i表示行,j表示每行的列
while (i < QUEEN)//满足继续搜索的条件
{
///没有到叶子结点情况下就继续搜索
while (j < QUEEN) //对i行的每一列进行探测,看是否可以放置皇后
{
if(valid(i, j)) //该位置可以放置皇后
{
a[i] = j; //第i行放置皇后,位置位j列
j = 0; //第i行放置皇后以后,需要继续探测下一行的皇后位置,
//所以此处将j清零,从下一行的第0列开始逐列探测
break;
}
else
{
++j; //继续探测下一列
}
}
///搜索到了叶子结点但是无解,直接回溯到上一行
if(a[i] == INITIAL) //第i行没有找到可以放置皇后的位置
{
if (i == 0) //回溯到第一行,仍然无法找到可以放置皇后的位置,
//则说明已经找到所有的解,程序终止
break;
else //没有找到可以放置皇后的列,此时就应该回溯
{
--i;
j = a[i] + 1; //把上一行皇后的位置往后移一列
a[i] = INITIAL; //把上一行皇后的位置清除,重新探测
continue;
}
}
//找到解
if (i == QUEEN - 1) //最后一行找到了一个皇后位置,
//说明找到一个结果,打印出来
{
printf("answer %d : \n", ++n);
print();
//不能在此处结束程序,因为我们要找的是N皇后问题的所有解,
//此时应该清除该行的皇后,从当前放置皇后列数的下一列继续探测。
j = a[i] + 1; //从最后一行放置皇后列数的下一列继续探测
a[i] = INITIAL; //清除最后一行的皇后位置
continue;
}
++i; //继续探测下一行的皇后位置
}
}
(3)结果打印
void print() //打印输出N皇后的一组解
{
int i, j;
for (i = 0; i < QUEEN; ++i)
{
for (j = 0; j < QUEEN; ++j)
{
if (a[i] != j) //a[i]为初始值
printf("%c ", '.');
else //a[i]表示在第i行的第a[i]列可以放置皇后
printf("%c ", '#');
}
printf("\n");
}
for (i = 0; i < QUEEN; ++i)
printf("%d ", a[i]);
printf("\n");
printf("--------------------------------\n");
}
来源:https://www.cnblogs.com/jainszhang/p/10701661.html