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)
相關文章
相關標籤/搜索