美文网首页
用JavaScript解决八皇后问题

用JavaScript解决八皇后问题

作者: 小小的开发人员 | 来源:发表于2019-05-20 11:23 被阅读0次

      八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案,1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。

      我们用JS实现该过程。

      为了演示方便,我们先在页面搭建网格:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        li {
            list-style: none;
        }
        #ul1 {
            height: auto;
            margin: 20px auto;
            overflow: hidden;
            border: 1px #000 solid;
            border-right: none;
            border-bottom: none;
        }
        #ul1 li {
            float: left;
            border: 1px #000 solid;
            border-left: none;
            border-top: none;
        }
    </style>
    <body>
    <ul id="ul1"></ul>
    </body>
    <script >
        let oUl = document.getElementById('ul1')
        let aLi = document.getElementsByTagName('li')
        let sizeGrid = 50
        let num = 8
        let iCount = 0
    
        init()
        function init() {
            createGird()
        }
        function createGird() {
            let len = num * num
            oUl.style.width = num * (sizeGrid + 1) + 'px'
            for (let i = 0; i < len; i++) {
                let oLi = document.createElement('li')
                oLi.style.width = sizeGrid + 'px'
                oLi.style.height = sizeGrid + 'px'
                oUl.appendChild(oLi)
            }
        }
    </script>
    </html>
    

      建立坐标系,为每一个网格挂载坐标信息:

    for (let i = 0; i < num; i++) {
        for (let j = 0; j < num; j++) {
            aLi[ i * num + j].x = j
            aLi[ i * num + j].y = i
            aLi[ i * num + j].innerHTML = j + ',' + i
        }
    }
    

      我们可以看出同一行的方格纵坐标相同,同一列的方格横坐标相同,同一斜线上的方格坐标相加或相减值是一样的。

    实现思路:

    1. 我们先给每个方格挂载索引index = -1,表示还未开始摆放。
    2. 从第一行的第一个方格开始摆放,此时index = 0,表示这是第一步,满足上图规则的(也就是在横纵斜方向)的方格也令其index = 0,index ! == -1的方格表示以后不能再摆放了。
    3. 从第二行搜索index === -1 的方格,令其index = 1,表示这是第二步,同样,满足横纵斜方向的也令其index = 1。
    4. 重复上述过程,当第8行时,仍然能找到一个index === -1的方格,表示是一种正确的摆放方式,我们记录下来。如果在下一行找不到index === -1的方格,则表示摆放方案不可行,我们需要回溯到上一行,改变上一行摆放方格的位置,再次重复步骤4。

    我们来实现上述过程:

    function setQueen(iQueen) {
    
        // 终止条件
        if (iQueen === num) {
            return
        }
    
        for (let i = 0; i < num; i++) {
            if (aLi[iQueen * num + i].index === -1) {
                aLi[iQueen * num + i].innerHTML = iQueen
                let x = aLi[ iQueen * num + i].x
                let y = aLi[ iQueen * num + i].y
                for (let j = 0; j < aLi.length; j++) {
                    if (aLi[j].index == -1 && (aLi[j].x == x || aLi[j].y == y || aLi[j].x - aLi[j].y == x - y || aLi[j].x + aLi[j].y == x + y))  {
                        aLi[j].index = iQueen // 不可以摆放的方格
                    }
                }
                setQueen(iQueen + 1) // 跳转到下一行
    
                // 回溯
                for (let j = 0; j < aLi.length; j++) {
                    if (aLi[j].index === iQueen) {
                        aLi[j].index = -1 // 把上一行的状态恢复
                    }
                }
            }
        }
    }
    

    我们来做一些统计:

    let iCount = 0 // 共有多少种摆放方案
    let postArr= [] // 其中一种方案具体的摆放
    let postAll = [] // 所有方案的摆放
    

    完整代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        li {
            list-style: none;
        }
        #ul1 {
            height: auto;
            margin: 20px auto;
            overflow: hidden;
            border: 1px #000 solid;
            border-right: none;
            border-bottom: none;
        }
        #ul1 li {
            float: left;
            border: 1px #000 solid;
            border-left: none;
            border-top: none;
            text-align: center;
            line-height: 50px;
        }
    </style>
    <body>
    <ul id="ul1"></ul>
    </body>
    <script >
        let oUl = document.getElementById('ul1')
        let aLi = document.getElementsByTagName('li')
        let sizeGrid = 50
        let num = 8
        let iCount = 0
        let postArr= []
        let postAll = []
    
        init()
        function init() {
            createGird()
            setQueen(0)
            console.log(iCount)
            console.log(postAll)
        }
        function createGird() {
            let len = num * num
            oUl.style.width = num * (sizeGrid + 1) + 'px'
            for (let i = 0; i < len; i++) {
                let oLi = document.createElement('li')
                oLi.style.width = sizeGrid + 'px'
                oLi.style.height = sizeGrid + 'px'
                oLi.index = -1
                oUl.appendChild(oLi)
            }
            for (let i = 0; i < num; i++) {
                for (let j = 0; j < num; j++) {
                    aLi[ i * num + j].x = j
                    aLi[ i * num + j].y = i
                    // aLi[ i * num + j].innerHTML = j + ',' + i
                    aLi[ i * num + j].innerHTML = aLi[ i * num + j].index
                }
            }
        }
        function setQueen(iQueen) {
    
            // 终止条件
            if (iQueen === num) {
                iCount++
                postAll.push(postArr.concat())
                return
            }
    
            for (let i = 0; i < num; i++) {
                if (aLi[iQueen * num + i].index === -1) {
                    aLi[iQueen * num + i].innerHTML = iQueen
                    postArr.push(aLi[iQueen * num + i])
                    let x = aLi[ iQueen * num + i].x
                    let y = aLi[ iQueen * num + i].y
                    for (let j = 0; j < aLi.length; j++) {
                        if (aLi[j].index == -1 && (aLi[j].x == x || aLi[j].y == y || aLi[j].x - aLi[j].y == x - y || aLi[j].x + aLi[j].y == x + y))  {
                            aLi[j].index = iQueen // 不可以摆放的方格
                        }
                    }
                    setQueen(iQueen + 1) // 跳转到下一行
    
                    // 回溯
                    postArr.pop()
                    for (let j = 0; j < aLi.length; j++) {
                        if (aLi[j].index === iQueen) {
                            aLi[j].index = -1 // 把上一行的状态恢复
                        }
                    }
                }
            }
        }
    </script>
    </html>
    

    相关文章

      网友评论

          本文标题:用JavaScript解决八皇后问题

          本文链接:https://www.haomeiwen.com/subject/zilhzqtx.html