/**
* 不知道大家有没有下过国际象棋,不过没关系,问题是这样的,在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。请设计程序算出结果,那种计算机语言不限。
*
* 棋盘模型
* $arr = [
* j 0, 1, 2, 3, 4, 5, 6, 7 // i
* [0, 0, 0, 0, 0, 0, 0, 0], // 0
* [0, 0, 0, 0, 0, 0, 0, 0], // 1
* [0, 0, 0, 0, 0, 0, 0, 0], // 2
* [0, 0, 0, 0, 0, 0, 0, 0], // 3
* [0, 0, 0, 0, 0, 0, 0, 0], // 4
* [0, 0, 0, 0, 0, 0, 0, 0], // 5
* [0, 0, 0, 0, 0, 0, 0, 0], // 6
* [0, 0, 0, 0, 0, 0, 0, 0], // 7
* ];
*
* @param int $n n个皇后
*
* @return void
*/
function queen($n = 8): void
{
$arr = []; // 初始化棋盘
$record = []; // 记录皇后位置,便于回溯
$max = $n - 1; // 最大索引
$a = 0; // 记录下列摆放皇后位置
$m = 0; // 皇后解法数
e('初始棋盘:');
// 生成棋盘
for ($i = 0; $i < $n; ++$i) {
for ($j = 0; $j < $n; ++$j) {
$arr[$i][$j] = 0;
e($arr[$i][$j], 'n');
}
e();
}
// 求解皇后所在棋盘位置
for ($i = 0; $i < $n; ++$i) {
for ($j = $a; $j < $n; ++$j) {
if ($a) $a = 0;
// 检验左上 右上 正上是否有皇后
$bool = true;
for ($k = 1; $k <= $i; ++$k) {
// 左上
$y = $i - $k;
$x = $j - $k;
if ($x >= 0 && $arr[$y][$x]) {
$bool = false;
break;
}
// 右上
$x = $j + $k;
if ($x < $n && $arr[$y][$x]) {
$bool = false;
break;
}
// 正上
if ($arr[$y][$j]) {
$bool = false;
break;
}
}
if ($bool) {
$arr[$i][$j] = 1;
$record[] = [$i, $j];
break;
}
// 回溯(当最后一列没有皇后) 做两件事 1、回到过去 2、过去数据置0
while ($j === $max) {
$tmp = array_pop($record); // 弹出数组最后一个皇后
if (!$tmp) die;
$i = $tmp[0]; // 重置行
$j = $tmp[1]; // 重置列
$arr[$i][$j] = 0; // 重置皇后
}
}
// 搜索其他解 思路:当摆放到最后一行,舍去这个解,将当前位置(列)加一 PS:无需验证皇后位置左侧数据,因为左侧数据全是验证过的
if ($i === $max) {
++$m;
// 打印皇后解法
h('h');
e($n . '皇后第' . $m . '种解法:');
for ($i = 0; $i < $n; ++$i) {
for ($j = 0; $j < $n; ++$j) {
e($arr[$i][$j], 'n');
}
e();
}
$tmp = array_pop($record); // 弹出数组最后一个皇后
$i = $tmp[0] - 1; // 行+1,因为循环结束(++)会加一
$a = $tmp[1] + 1; // 列-1
$arr[$tmp[0]][$tmp[1]] = 0; // 重置皇后
// 当列已经是最后一列,列+1将会超出棋盘,所以应该行-1,然后重复上面的操作
if ($a > $max) {
$tmp = array_pop($record);
$i = $tmp[0] - 1;
$a = $tmp[1] + 1;
$arr[$tmp[0]][$tmp[1]] = 0;
}
}
}
}
queen(6);
运行结果: