八皇后的递归解法

最近在看PiL3,今天在做习题的时候遇见了八皇后问题,当时示例代码并没有仔细看,等到写的时候发现老是有问题。后来去查了下八皇后问题的描述,发现自己虽然知道这个问题很久了却没有真正理解过,真为自己汗颜。

八皇后问题

以下资料来自WikiPedia:

八皇后问题是一个以国际象棋为背景的问题:如何能够在8×8的国际象棋棋盘上放置八个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任两个皇后都不能处于同一条横行、纵行或斜线上。八皇后问题可以推广为更一般的n皇后摆放问题:这时棋盘的大小变为n×n,而皇后个数也变成n。当且仅当n = 1或n ≥ 4时问题有解。

一个简单的递归算法

这个算法来自于PiL3中,我在做习题的时候将其自己实现了一遍,思路是一样的,下面介绍一下。
首先定义了2个全局变量,N表示棋盘的大小,solved代表问题是否已解决。
printBoard用来打印当前棋盘,皇后用X表示,空格用-表示。
validPos的作用是判断当前棋盘上能否在n行pos列上放置新棋子。

addQueen是算法的核心函数,也是被递归调用的函数。board代表当前的棋盘,n表示当前放置棋子的行数。
当n大于N时表明当前棋盘已经有解了,直接打印即可。
当n小于N时,尝试当前行n上在pos列放置棋子,如果位置合适则在棋盘上记录该棋子,并继续在下一行添加新棋子(调用addQueen(board,n+1))。如果不合适,则舍弃当前棋盘,不再递归调用自身,我一开始没有仔细看这里,导致我没理解这个解法如何只对符合规则的棋盘继续求解。

总结:与最常用最容易想到的回溯法相比,递归的方法显得简单粗暴,不过代码也确实简单了不少。

Lua实现如下:

local N=8
local solved=false
local function printBoard(board)
    if solved then
        return
    end
    for i=1, N do
        for j=1, N do
            io.write(board[i]==j and "X" or "-", " ")
        end
        io.write("\n")
    end
    io.write("\n")
    solved = true
end
local function validPos(board, row, pos)
    for i=1, row-1 do
        if (board[i] == pos) or
            (row-i == math.abs(pos - board[i])) then
            return false
        end
    end
    return true
end

local function addQueen(board, n)
    if n>N then
        printBoard(board)
    else
        for pos=1, N do
            if validPos(board, n, pos) then
                board[n]=pos
                addQueen(board, n+1)
            end
        end
    end
end

addQueen({},1)

你可能感兴趣的:(八皇后的递归解法)