Day28:八皇后问题- 8 Queens Puzzle

https://ithelp.ithome.com.tw/upload/images/20210928/20128604lgEZqCdYrQ.jpg

八皇后问题可以说是一道相当经典的演算法题目,以西洋棋为背景,如何在一个8x8的棋盘上摆放八个皇后的棋子,让任何一个皇后无法吃掉其中一个皇后,也是就是任何一个皇后的横行、纵行、斜线上都不会出现其它的皇后,後来八皇后问题也被衍生为N皇后问题 - 在N*N的棋盘上放置N个皇后,试问有几种解法?就让我们用回溯法来解N皇后的问题吧!

https://ithelp.ithome.com.tw/upload/images/20210928/20128604qSFfNrIfoe.png

图片来源:https://medium.com/nerd-for-tech/genetic-algorithm-8-queens-problem-b01730e673fd

先用四皇后来推演一下流程

  1. 假设现在有个4*4的棋盘,我们先将第一个皇后放在第一个格子里面
    https://ithelp.ithome.com.tw/upload/images/20210928/20128604qlUtOKYcx4.png

  2. 由於一个直行只能有一个皇后,所以接下来将第二个皇后放在第二行的第一个,不过因为皇后的横列不可以有其它皇后,所以往下挪动一格
    https://ithelp.ithome.com.tw/upload/images/20210928/20128604j9O8OaIdgq.png

  3. 真不巧,斜线上也不能出现其它皇后,因此要再往下挪动一格
    https://ithelp.ithome.com.tw/upload/images/20210928/2012860463K0xTDnF2.png

  4. 因此第二个皇后摆放在这个位置
    https://ithelp.ithome.com.tw/upload/images/20210928/201286045UVfCrOte2.png

  5. 接下来放置第三个皇后,但会发现一个问题,不管放在哪个位置都不行,因次要使用回溯法来调整第二个皇后的位置,把他往下移动一格
    https://ithelp.ithome.com.tw/upload/images/20210928/20128604NZP87EJXDJ.png

  6. 调整完之後第三个皇后也放好了
    https://ithelp.ithome.com.tw/upload/images/20210928/20128604G0jhOja3nA.png

  7. 不过在摆放第四个皇后的时候,又发生了一样的问题,只好用回溯法再次倒回去
    https://ithelp.ithome.com.tw/upload/images/20210928/201286047X51NA142z.png

  8. 重覆先前的步骤之後,总算能够成功摆放四个皇后了!
    https://ithelp.ithome.com.tw/upload/images/20210928/20128604K4KtbbFkAx.png

用js实作

const NQueens = (n) => {
    let answer = 0;
    let arr = [];
    for (let i = 0; i < n; i++) {
        arr.push(Array.from({ length: n }).fill(null));
    }

    let i = 0; //第几列(横向)
    let j = 0; //第几行(直向)
    let loop = true;
    while (loop) {
        console.log("i", i, "j", j);
        arr[i][j] = "Q";
        console.log("arr", arr);
        //检查横行、纵行、斜线是否有其它Q的flag
        let checkQExist = false;
        let k = 0;
        while (k < i) {
            //确认当前的Q上方是否有其它Q的存在
            if (arr[k][j] === "Q") {
                checkQExist = true;
            }
            k++;
        }
        k = 0;
        while (k < j) {
            //确认当前的Q左边是否有其它Q的存在
            if (arr[i][k] === "Q") {
                checkQExist = true;
            }
            k++;
        }
        k = 1;
        let l = -1;
        while (i + k < n && j + l >= 0) {
            //确认当前的Q对角线(左下角)是否有其它Q的存在
            if (arr[i + k][j + l] === "Q") {
                checkQExist = true;
            }
            k++;
            l--;
        }
        k = -1;
        while (i + k >= 0 && j + k >= 0) {
            //确认当前的Q对角线(右上角)是否有其它Q的存在
            if (arr[i + k][j + k] === "Q") {
                checkQExist = true;
            }
            k--;
        }
        if (!checkQExist) {
            console.log("Q can put here");
            console.log(arr);
            //已经放到最後一行了
            if (j === n - 1) {
                answer++;
                console.log("perfect solution");
                console.log(arr);
                arr[i][j] = null;
                i++; //往下一列
            } else {
                //往下一行
                i = 0;
                j++;
            }
        }

        if (checkQExist) {
            console.log("Q exist!!");
            console.log(arr);
            arr[i][j] = null; //不能放这格所以要清空
            i++;
        }

        //检查是否超出边界
        const checkBoundary = () => {
            j--;
            for (let r = 0; r < arr.length; r++) {
                if (arr[r][j] === "Q") {
                    arr[r][j] = null;
                    console.log("r and j is", r, j);
                    i = r + 1;
                    break;
                }
            }
        };

        while (i >= n) {
            //如果横列超过n 需检查前一行
            checkBoundary();
            if (j < 0) {
                console.log("done");
                loop = false;
                break;
            }
        }
    }
    console.log("Number of solution", answer);
};

NQueens(4); //2

单看程序码实在是过於抽象,为了帮助理解所以将阵列印出来看,就会比较清楚整体的运作流程为何
https://ithelp.ithome.com.tw/upload/images/20210928/20128604A2syyRXPOL.png

为了验证程序码是否正确,将input改为8,结果运算时间出乎我的意料,真的是所谓的让子弹飞一会,非常的耗时,一度还让我以为是否写了无穷回圈/images/emoticon/emoticon04.gif,还好最後成功印出92

维基百科提供的N皇后解答
https://ithelp.ithome.com.tw/upload/images/20210928/20128604pXFlLTWVrh.png


<<:  CSS 定位属性(DAY15)

>>:  Day 16: AWS Config简介

Day-24 快速面试之考题大公开!(3)

听听其他人对於快速面试的应对。 有被问到专案的优化方式如何,当时我答不好(冏)後来听到组员回答的很...

运动控制

运动控制:关键词是“控制理论”; 控制系统可以视为具有四种机能的系统:量测(检测参数)、比较、计算及...

[Day 2] 差异性安装

如需在地端环境操作 那需要去理解 什麽是node JS 什麽是NPM 需要参照 本地安装 使用 np...

IT铁人第29天 Elasticsearch 使用python查询资料 Aggregations:Terms

今天的文章要介绍的是Bucket Aggregations的一种聚合方式,其实Metrics Agg...

30天轻松学会unity自制游戏-增加摇杆&修改画布

预计是制作手机游戏,来帮游戏加装一个摇杆,先到Unity商城,Asset Store有免费的摇杆可以...