php八皇后问题,N皇后问题

20 篇文章 0 订阅
/**
 * 不知道大家有没有下过国际象棋,不过没关系,问题是这样的,在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);

运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值