这是我解决八皇后难题的swift代码
八皇后之谜是把八个国际象棋皇后放在一个8×8的棋盘上,这样就不会有两个皇后互相威胁。因此,解决方案要求两个皇后不共享同一行、列或对角线。八皇后之谜是更一般的n皇后问题的一个例子,即在n×n棋盘上放置n个皇后,除n=2或n=3外,所有自然数n都有解 然而,有没有人能帮我解决这个问题,在递归方法中无休止的循环 附言:你可以复制/粘贴到游乐场,然后试试看,谢谢这是我解决八皇后难题的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]()
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()
看来您在理解递归的概念方面遇到了困难。递归并不意味着一切都成为递归调用。在functiondropQueen
中,您使用的是递归调用,就好像它们是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)
}