Lua实现的八皇后问题

来自《Lua程序与设计》第二节- 八皇后问题


输出所有解的解法

书中提供的源代码,加注了自己的注释。

N = 8
--[[
 N为棋盘规模
 a为一维数组,保存第i个皇后所在的列数
]]

-- 检查是否可以将第n个皇后放在第n行第c列(前n-1行的皇后已经放好)
function isplaceok(a,n,c)
 -- 检查前n-1个皇后是否与(n,c)位置冲突
    for i = 1, n - 1, 1 do
        if a[i] == c or -- 是否同一列
           a[i] - i == c - n or --是否同一对角线 (?)
           a[i] + i == c + n then --是否同一对角线 (?)
            return false
        end
    end
    return true -- 不会被攻击 位置有效
end

-- 用于在找到解后打印棋盘
function printsolution(a)
    for i = 1, N do
        for j = 1, N do
            io.write(a[i] == j and "X" or "-", " ")
        end
        io.write("\n")
    end
    io.write("\n")
end

-- 已经找到前n-1皇后的位置
-- 存放于a中
-- 寻找第n个皇后可摆放的位置
function addqueen(a,n)
    if n > N then
        printsolution(a)
        return true
    else
-- 逐列检查能否摆放第n个皇后
        for c = 1, N do
            if isplaceok(a, n, c) then
                a[n] = c
                if addqueen(a, n+1) then
                    return true
                end
            end
        end
    end
end

-- 启动方式
addqueen({}, 1)

书后练习

1. 修改八皇后问题的程序,使其在输出第一个解后即停止运行。

修改addqueen函数即可。

-- 已经找到前n-1皇后的位置
-- 存放于a中
-- 寻找第n个皇后可摆放的位置
function addqueen(a,n)
    if n > N then
        printsolution(a)
        return true
    else
-- 逐列检查能否摆放第n个皇后
        for c = 1, N do
            if isplaceok(a, n, c) then
                a[n] = c
                if addqueen(a, n+1) then
                    return true
                end
            end
        end
    end
end
2. 解决八皇后问题的另一种方式是,先生成1-8之间的所有排列,然后依次遍历这些排列,检查每一个排列是否是八皇后问题的有效解。请使用这种方法修改程序并对比性能差异。

一定是原本的方法效率更高…1-8之间的所有排列一共有8的8次幂个,检查每个排列是否合法又是O(n^2)的复杂度,效率会很低。只看isplaceok函数调用次数的话,原来的方法一共调用isplaceok函数876次,生成所有排列的方法生成了8的8次幂个排列,每个排列调用isplaceok的次数最少1次,最多8次,整体也在5千万次以上。
实际测了一下,用的在线编辑器,直接爆掉了。又重新用本地的lua跑了一下。调用isplaceok的次数为50889536次。(妈呀)

N = 8
--[[
 N为棋盘规模
 a为一维数组,保存第i个皇后所在的列数
]]
count = 0
-- 检查是否可以将第n个皇后放在第n行第c列(前n-1行的皇后已经放好)
function isplaceok(a,n,c)
 count = count + 1
 -- 检查前n-1个皇后是否与(n,c)位置冲突
 for i = 1, n - 1, 1 do
  if a[i] == c or -- 是否同一列
   a[i] - i == c - n or --是否同一对角线 (?)
   a[i] + i == c + n then --是否同一对角线 (?)
   return false
  end
 end
 return true -- 不会被攻击 位置有效
end

-- 用于在找到解后打印棋盘
function printsolution(a)
 for i = 1, N do
  for j = 1, N do
   io.write(a[i] == j and "X" or "-", " ")
  end
  io.write("\n")
 end
 io.write("\n")
end

-- 已经放置前n-1皇后
-- 存放于a中
-- 放置第n个皇后
function addqueen(arrays, a, n)
 if n > N then
  table.insert(arrays, a)
 else
  -- 逐列检查能否摆放第n个皇后
  for c = 1, N do
   local b = {}
   for k, v in pairs(a) do
    b[k] = v
   end
   b[n] = c
   addqueen(arrays, b, n+1)
  end
 end
end

function getsolution()
 local posibles = {}
 addqueen(posibles, {}, 1)
 for _, v in pairs(posibles) do
  local ok = true
  for i = 1, N do
   ok = isplaceok(v, i, v[i])
   if not ok then
    break
   end
  end
  if ok then
   printsolution(v)
  end
 end
end

-- 启动方式
getsolution()
io.write("\n",count)
posted @ 2020-02-06 22:02  Zoey-L  阅读(...)  评论(...编辑  收藏