这是我解决八皇后难题的swift代码

这是我解决八皇后难题的swift代码,swift,recursion,puzzle,n-queens,Swift,Recursion,Puzzle,N Queens,八皇后之谜是把八个国际象棋皇后放在一个8×8的棋盘上,这样就不会有两个皇后互相威胁。因此,解决方案要求两个皇后不共享同一行、列或对角线。八皇后之谜是更一般的n皇后问题的一个例子,即在n×n棋盘上放置n个皇后,除n=2或n=3外,所有自然数n都有解 然而,有没有人能帮我解决这个问题,在递归方法中无休止的循环 附言:你可以复制/粘贴到游乐场,然后试试看,谢谢 class ChessBoard { var limit: Int var queens = [Queen]()

八皇后之谜是把八个国际象棋皇后放在一个8×8的棋盘上,这样就不会有两个皇后互相威胁。因此,解决方案要求两个皇后不共享同一行、列或对角线。八皇后之谜是更一般的n皇后问题的一个例子,即在n×n棋盘上放置n个皇后,除n=2或n=3外,所有自然数n都有解

然而,有没有人能帮我解决这个问题,在递归方法中无休止的循环

附言:你可以复制/粘贴到游乐场,然后试试看,谢谢

class ChessBoard {

    var limit: Int
    var queens = [Queen]()

    init(limit: Int) {
        self.limit = limit
    }

    // Check if (i,j) is a safe position for queen
    func isSafeForQueen(atRow row: Int, col: Int) -> Bool {

        for q in queens {
            // not in same row
            if q.row == row { return false }
            // not in same column
            if q.col == col { return false }
            // not in same diagol line
            if abs(q.row-row) == abs(q.col-col) { return false }
        }

        return true
    }

    // recursive method
    func dropQueen(atRow r: Int, c: Int) {

        // running into last row
        if r == limit {
            if queens.count < 8 {
                queens.removeLast()
                let q = queens.last!
                dropQueen(atRow: q.row, c: q.col+1)
            }
            output() // if success, log out the positions
            return
        }
        // running into last column of current row
        if c == limit {
            queens.removeLast()
            let q = queens.last!
            // if no position for queen at current row, then back to last row
            dropQueen(atRow: r-1, c: q.col+1)
        }
        // if this postion is safe for queen, then drop the queen and try next row; if not, try next spot
        if isSafeForQueen(atRow: r, col: c) {
            let q = Queen(row: r, col: c)
            queens.append(q)
            dropQueen(atRow: r+1, c: c)
        } else {
            dropQueen(atRow: r, c: c+1)
        }
    }

    func play() {
        dropQueen(atRow: 0, c: 0) // game will start at(0,0)
    }

    func output() -> String {
        var s = ""
        for q in queens {
            s += "(\(q.row),\(q.col))"
        }
        return s
    }
}

struct Queen {
    var row: Int
    var col: Int
}

// Tesing:
let b = ChessBoard(limit: 8)
//b.play()
类棋盘{
风险限额:整数
变量queens=[Queen]()
初始化(限制:Int){
self.limit=限制
}
//检查(i,j)是否为皇后的安全位置
func isSafeForQueen(atRow行:Int,列:Int)->Bool{
皇后区的q{
//不在同一行
如果q.row==行{返回false}
//不在同一列中
如果q.col==col{return false}
//不在同一条对角线上
如果abs(q.row-row)==abs(q.col-col){return false}
}
返回真值
}
//递归方法
func dropQueen(atRow r:Int,c:Int){
//撞到最后一排
如果r==极限{
如果queens.count小于8{
皇后区
让q=皇后区最后一个!
dropQueen(atRow:q.row,c:q.col+1)
}
output()//如果成功,则注销位置
返回
}
//正在运行到当前行的最后一列
如果c==极限{
皇后区
让q=皇后区最后一个!
//如果当前行中没有皇后的位置,则返回到最后一行
dropQueen(atRow:r-1,c:q.col+1)
}
//如果这个位置对女王来说是安全的,那么放下女王试试下一排;如果不是,试试下一排
如果isSafeForQueen(箭头:r,柱:c){
设q=Queen(行:r,列:c)
皇后区追加(q)
dropQueen(atRow:r+1,c:c)
}否则{
dropQueen(atRow:r,c:c+1)
}
}
func play(){
dropQueen(atRow:0,c:0)//游戏将从(0,0)开始
}
func output()->字符串{
var s=“”
皇后区的q{
s+=“(\(q.row),\(q.col))”
}
返回s
}
}
结构女王{
变量行:Int
变量列:Int
}
//测试:
设b=棋盘(限制:8)
//b、 play()

看来您在理解递归的概念方面遇到了困难。递归并不意味着一切都成为递归调用。在function
dropQueen
中,您使用的是递归调用,就好像它们是gotos一样

特别是这个,

dropQueen(atRow: r-1, c: q.col+1)
这显然是一种回溯的尝试。下定决心;要么回溯,要么使用递归!在递归中,返回先前的决策是一个
返回
。如有必要,返回一个布尔值,让调用方知道递归调用是否找到了解决方案(
returntrue
)或没有(
returnfalse
)。如果您希望您的程序找到所有可能的解决方案,而不仅仅是第一个解决方案,那么您不需要这样做

另一个引起我注意的电话:

dropQueen(atRow: r, c: c+1)
递归调用在这里是过分的,而且令人困惑;使用循环扫描所有可能的列。顺便说一下,通过进行此更改,您将发现整个第二个函数参数变得多余

这只给我们留下了一个反复的呼唤;这就足够了

dropQueen(atRow: r+1, c: c)
正如瓦卡瓦马所指出的,第二个参数
c:c
似乎是错误的。当你前进一行(
r+1
)时,为什么要排除你在棋盘上放置的最后一个皇后左边的所有内容

如果你想做递归,那么想想你的递归函数应该做什么。通常,您希望它在已被r皇后占据的板上放置(8-r)更多皇后。您正在一行一行地工作,因此在您的方法中,r只是当前的行号。想一想如何用r+1行的解决方案来表达r行问题的解决方案。对最后一行进行特殊例外处理;一旦r等于极限,则解是平凡的(需要放置零皇后);你完了

哦,请重命名函数
dropQueen
;这个名字清楚地表明你是以错误的心态在做这件事的。到现在为止,你应该能够想出更合适的方法


编辑: 您在这项工作中付出了相当大的努力,因此我将与您分享我的解决方案。它使用您的原始代码(如您的问题所示),但函数
dropQueen
完全重写(少一个参数)。注意它是多么的简短和简单;这是递归的典型特征

func dropQueen(atRow r: Int) {
    if queens.count < limit {
        for col in 0...limit-1 {
            if isSafeForQueen(atRow: r, col: col) {
                let q = Queen(row: r, col: col)
                queens.append(q)
                dropQueen(atRow: r+1)
                if queens.count == limit {
                    return
                }
                queens.removeLast()
            }
        }
    }
}
func dropQueen(atRow r:Int){
如果queens.count<限制{
对于0中的列…限制-1{
如果isSafeForQueen(atRow:r,col:col){
设q=Queen(行:r,列:col)
皇后区追加(q)
dropQueen(atRow:r+1)
如果queens.count==限制{
返回
}
皇后区
}
}
}
}
另外,如果将
return
替换为
println(output())
,则程序将打印所有92个解决方案。您可以在以下位置看到这一点:

我的更改代码:

首先,我制作dropQueen()和takeQueen()是为了特定的目的:

func dropQueen(atRow r: Int, col: Int) {
    let q = Queen(row: r, col: col)
    queens.append(q)
}

func takeLastQueen() -> (Int, Int) {
    let q = queens.last
    if q != nil {
        queens.removeLast()
    }
    // return (-1,0) means it's time to stop the game
    return q != nil ? (q!.row, q!.col) : (-1,0)
}
然后,使用for循环迭代同一行中的每一列,并仅使用递归进行回溯(当然,我重命名了名为makeStep()的函数,并在row==limit时首先添加了“Done”检查)


一旦它找到了一个结果,它不会停止,直到我在操场上得到27个结果。我还不明白为什么是27岁,但你们帮了我大忙,真是太棒了

非常感谢。在我看到你的answe之前
func makeStep(atRow r: Int, fromCol: Int) {

    if r == limit {
        // When find a resolution, keep the result
        // But it won't stop
        output()
    } else if r < 0 {
        // Time to stop game
        // but why just 27 resolutions ?
        return
    }

    var isQueenAtCurrentRow = false

    for c in fromCol..<limit {
        if isSafeForQueen(atRow: r, col: c) {
            dropQueen(atRow: r, col: c)
            isQueenAtCurrentRow = true
            break
        }
    }

    // Only use recursion for backtrack
    if isQueenAtCurrentRow {
        // if queen is set, go to next row
        makeStep(atRow: r+1, fromCol: 0)
    } else {
        // if failed, go back to last row and try next spot
        let (r,c) = backTrackForNext()
        makeStep(atRow: r, fromCol: c)
    }
}
func backTrackForNext() -> (Int, Int) {
    // find last row
    var (r,c) = takeLastQueen()
    c++ // find next spot
    if c == limit {
        // if hit end of column, go back again
        backTrackForNext()
    }
    return (r,c)
}