题目
例如,其中一种解:
1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 1 0 0
0 0 1 0 0 0 0 0
0 0 0 0 0 0 1 0
0 0 0 1 0 0 0 0
思路
我们可以将棋盘用一个二维数组表示,棋盘上用0代表不同的位置,1表示皇后所在的位置。
由于每一行只能有一个皇后,并且皇后不能处于同一列,所以,每一行皇后位置的下标必然不同且唯一。
例如,我们可以将上图皇后在每一行的位置记录为: 0 4 7 5 2 6 1 3
如果按照下标从0开始记数,那图中的结果可以表示为:1 5 8 6 3 7 2 4
通过观察发现,原来8皇后问题可以看成将数字1-8全排列的问题,但是全排列的结果要满足一定要求。
那这么要求是什么呢? 那就是所有的皇后不能在同一条斜线上(反斜线也不行)。我们以第图中的第5行为例。如果第5行的位置在坐标3上,
那么第1行不能在 3+(5-1) = 7
那么第2行不能在 3+(5-2) = 6
那么第3行不能在 3+(5-3) = 5 且 3-(5-3) = 1
那么第4行不能在 3+(5-4) = 4 且 3-(5-4) = 2
那么第6行不能在 3+(6-5) = 2 且 3-(6-5) = 2
那么第7行不能在 3+(7-5) = 5 且 3-(7-5) = 1
那么第8行不能在 3+(8-5) = 6
不难发现:每行的下标之间的距离,不能等于每行之间的距离。这里的距离可以用两数相减的绝对值来计算。
代码
#include <iostream>
#include <math.h>
using namespace std;
// 判断条件
// 下标0-7分别对应正方体编号1-8的顶点
bool checking(int data[8])
{
bool ok = true;
for (int i = 0; i < 8; ++i)
{
for (int j = i + 1; j < 8; ++j)
{
if (abs(data[j]-data[i]) == j - i)
{
ok = false;
return ok;
}
}
}
return ok;
}
// 全排列
void Permutation(int data[],int position = 0, int len = 8)
{
if (position == len - 1 && checking(data))
{
for (int i = 0; i < len; ++i)
{
cout << data[i] << ' ';
}
cout << endl;
// 找到一种解,就退出了
// exit(EXIT_SUCCESS);
return;
}
for (int i = position; i < len; ++i)
{
std::swap(data[position], data[i]);
Permutation(data, position + 1);
std::swap(data[position], data[i]);
}
}
int main()
{
int data[8] = {1,2,3,4,5,6,7,8};
Permutation(data);
return EXIT_SUCCESS;
}