兩個版本。思路大體相同,都是用的回溯。不過資料結構上的版本不太容易懂。先寫上來吧。
struct queen ;
bool
operator==(queen const& q)const
bool
operator != (queen const& q)const
};
static
int ncheck = 0;
static
int nresult = 0;
void placequeens(int n)
else
//這裡用if,else,因為不能保證回溯後是否能繼續執 //行,乾脆用分支,用下一次的if判斷來保證
if (q.y //如果找到乙個可以放置的地方,就將其入棧,判斷能否 //輸出完整的解,並搜尋下一行,從第0列開始
}while ((q.x >0) || (q.y < n))//退出迴圈的條件是搜尋到第0行第n列
}
一些總結:
①退出迴圈的條件是搜尋到第0行第n列
②進入程式後會發生以下幾種情況:
(一)滿足迴圈條件,沒有越界,進過迴圈判斷後可以放置,並且不是最後一行,那麼下一步就是入棧並執行下一行
(二)滿足迴圈條件,沒有越界,進過迴圈判斷後可以放置,是最後一行,下一步仍然是執行下一行,但是會回溯
(三)滿足迴圈條件,沒有越界,進過迴圈判斷後沒有可以放置的位置,那麼經過迴圈之後q.y應該是等於n的,跳過入棧,到下次迴圈會回溯
(四)solu.size() >= n,即棧滿了,此時像越界一樣處理,回溯並y++
(五)q.y >=n,越界,需要回溯
③相比於遞迴來說比較難理解,但是空間複雜度較少,而且通過剪枝也得到了很好的優化。
///
八皇后遞迴版
const
int normalize = 9;
int num;
int q[9];
bool s[9];
bool l[17]; //用來存放對角線標記的
bool y[17];
void
try(int col)
for (int row = 1; row <= 8; row++)}}
int main()
try(1);
return
0;}
感覺遞迴版沒啥好說的,簡單便捷,回溯也方便》。。。
11.26新增
這次是lisp版的,太簡潔了,lisp果然是神書…
(define
(queens board-size)
(define
(queen-cols k)
(if (=k
0)(list
empty-board)
(filter
(lambda
(positions)
(safe? k positions))
(flatmap
(lambda
(rest-of-queens)
(map
(lambda
(new-row)
(adjoin-position new-row k rest-of-queens))
(enumerate-interval
1 board-size)))
(queen-cols
(-k1))))))
(queen-cols board-size))
(define empty-board '())
;定義空棋盤
(define
(adjoin-position
new-row k rest-of
-queens)
(cons new
-row rest-of
-queens))
;新增皇后
刪除不安全的皇后
(define
(safe? k position)
(iter-check
(car position)
(cdr position)
1))(define
(iter-check row-of-new-queen rest-of-queens i)
(if (null? rest-of-queens)
; 下方所有皇后檢查完畢,新皇后安全
#t(let
((row-of-current-queen
(car rest-of-queens)))
(if (or
(= row-of-new-queen row-of-current-queen)
; 行碰撞
(= row-of-new-queen (+
i row-of-current-queen))
; 右下方碰撞
(= row-of-new-queen (-
row-of-current-queen i)))
; 左下方碰撞
#f(iter-check row-of-new-queen (cdr rest-of-queens)
; 繼續檢查剩餘的皇后
(+ i1))))))
; 更新步進值
解釋:rest-of-queens是在前k-1列防止k-1個皇后的一種方式,new-row是在第kie放置所考慮的行編號。adjoin-position是將乙個新的行列格局加入到乙個格局集合;empty-board是乙個空的格局集合,safe?是確定新的格局中的kie的皇后是否是安全的。
讓我們從表達方式開始說明。
表達出來就是list(6 3 1 7 5 8 2 4)
因為題目要求給出八皇后問題的所有解法,所以 queens 求出的最終結果將是乙個二維列表: (list (list 6 3 1 7 5 8 2 4) (list …) (list …) …) 。
(define
(safe? k position)
(iter-check
(car position)
(cdr position)
1))(define
(iter-check row-of-new-queen rest-of-queens i)
(if (null? rest-of-queens)
; 下方所有皇后檢查完畢,新皇后安全
#t(let
((row-of-current-queen
(car rest-of-queens)))
(if (or
(= row-of-new-queen row-of-current-queen)
; 行碰撞
(= row-of-new-queen (+
i row-of-current-queen))
; 右下方碰撞
(= row-of-new-queen (-
row-of-current-queen i)))
; 左下方碰撞
#f(iter-check row-of-new-queen (cdr rest-of-queens)
; 繼續檢查剩餘的皇后
(+ i1))))))
; 更新步進值
safe 這個函式,呼叫了乙個iter-check函式,iter-check函式傳入的引數有三個(其實是兩個),新加入的行,還有之前的行,在這裡之前的行我們已經可以保證它是符合規定的。
然後就是遍歷檢查了,之前存的時候從上向下存的乙個好處在這就能體現了,從上向下便利檢查每乙個數字,並且也要看對角線是否滿足要求,如果到最後都檢查完了就是成功了,否則就是失敗。
八皇后問題
八皇后問題 ackarlix 八皇后問題是乙個古老而著名的問題,是回溯演算法的典型例題。該問題是十九世紀著名的數學家高斯 1850 年提出 在 8x8格的西洋棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行 同一列或同一斜線上,問有多少種擺法。高斯認為有 76種方案。1854 年在...
八皇后問題
include iostream.h int a 8 8 棋盤 int r 8 結果 int i,j int count 0 void init i j 0 int judge int x,int y for int mi x 1,mj y mi 1 mi for int ri x 1,rj y 1...
八皇后問題
package quess 由於八個皇后的任意兩個不能處在同一行,那麼這肯定是每乙個皇后佔據一行。於是我們可以定義乙個陣列columnindex 8 陣列中第i個數字表示位於第i行的皇后的列號。先把columnindex的八個數字分別用0 7初始化,接下來我們要做的事情就是對陣列columninde...