美文网首页
用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解决八皇后问题

      八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出...

  • 《Lua程序设计》-2.八皇后问题

    1.解决八皇后问题,必须认识到每一行只能有一个皇后

  • 利用递归解决八皇后问题

    1.什么是八皇后问题? 游戏的一种,感兴趣的小伙伴可以去玩一下。规则如下:在 8 * 8 的棋盘上,任何两个皇后都...

  • 11.数据结构—八皇后问题(回溯法)

    11.1 八皇后问题 八皇后问题是以国际象棋为背景的问题:有八个皇后(可以当成八个棋子),如何在 88 的棋盘中放...

  • Python用迭代(yield)和递归解决八皇后问题

    问题 ​国际象棋的皇后行走具有最高的灵活性,可以横、竖、斜共八个方向无限步行走。你需要将国际象棋8个皇后放在棋盘上...

  • 算法(03)回溯

    八皇后问题

  • 生成器

    一个非常棒的递归生成器 利用递归生成器解决八皇后问题

  • 八皇后问题(N皇后问题)

    八皇后问题是一个经典的递归回溯问题。 描述 八皇后问题是在一个 8*8 的棋盘上放置皇后,要求其放置后满足同一行,...

  • 八皇后问题

    八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在...

  • 八皇后问题

    问题的类别是回溯(backtrace). 回溯通常用递归实现。回溯中注意边界问题,避免越界。同时,剪枝可以减少ca...

网友评论

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

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