n皇后問題是大家在遞迴裡會碰到的乙個經典問題。以前高中我學dfs的時候,老師首先讓我看的就是八皇后。
不過這皇后的時間複雜度大家可想而知了。而接下來的位運算將這個效率重新提到乙個高度。
我是以前在matrix67大牛那裡學的,最近資料結構實驗剛好碰到n皇后,就在這裡「複述」一遍吧。
code:
void
doans(
intr,
intld,
intrd)
} else
sum++;
}
乍一看有點模糊吧?沒錯,這就是n皇后的遞迴函式了。我們乙個個來解析。
首先uplimit是(1 << n) - 1,如果n是8的話uplimit就是255,看做二進位制就是11111111。聰明的人一看就知道了,這裡每一位就代表乙個皇后。
而r代表每一列能放與否,如10001110就代表第2、3、4、8個能放。
所以開始乙個if來判斷皇后放齊了沒。如果齊了,顯然r也要等於11111111。
還有ld和rd分別是對角線的各位能放與否。
我們來看看下圖(from matrix67):
假設我們已經遞迴到第三行了(左圖),這裡可以看出r為101010也就是說
二、四、六可以放。ld是100100(藍色線),二、三、五、六可以放,rd為000111,。
好的,那麼哪幾個可以放呢?我們將r、ld、rd或運算一遍(或者r有或者ld有或者rd有),得到101111,也就是說這三個合起來的話就只能放第二格了。然後我非運算一遍,得到的是010000,非運算之後1代表可以放,0代表不可以放了。然後我們再與運算一遍就得到可以放的位置了:010000。
code:
intp = pos & (~pos + 1);
這一句我們可以用
code:
intp = pos & -pos;
來代替,什麼意思呢?其結果是取出最右邊的那個1。比如我們有乙個數字pos是10010,那麼p得到的結果就是10了。那麼上面那個010000得到的結果就是10000了。然後我們更新一遍pos:讓它減去p也就是10000,那麼pos得到的結果就是000000。也就是說下一次迴圈就跳出了。
看看傳進去的三個引數:
r + p為下一層遞迴的r,即10000 + 101010 = 111010那就相當於放進第二個了。
(ld + p) << 1為下一層的ld,即(100100 + 10000) << 1為(110100) << 1也就是1101000了。當然,在下一層遞迴的時候第乙個1將會被uplimit & ~(r | ld | rd)截掉成為101000。
(rd + p) >> 1為下一層的rd,即(000111 + 10000) >> 1為(010111) >> 1也就是001011。
那麼在新的一層裡又有新的r和ld還有rd組合了。
主題的思路就是這樣子的。
code:
/*** @brief n皇后問題 - 位運算版
* @author 朱凱迪
* 2010/11/22
*/#include
#include
using
namespace
std;
/** 方案鍊錶 */
list
> sol;
/** 棋盤大小 */
intn;
/** 棋盤擺滿時的數字 */
intuplimit;
void
print()
for(int
j = 0; j
"■");
printf("○"
);
for(
intj = cnt + 1; j
"■");
printf("/n"
);
} printf("/n"
);
} void
doans(
intr,
intld,
intrd)
} else
print();
} int
main()
return
0;
}
位運算解決N 皇后問題
描述 位運算是定義在整數上的運算。但在做位運算的時候,並不把整數看作整數,而是將它們看做一系列二進位制數字,逐位進行運算。位運算有6種,他們的名稱,運算子及運算規則如下 與 and 5 6 4 101 110 100 或 or 5 6 7 101 110 111 異或 xor 5 6 3 101 1...
位運算n皇后 洛谷1219
老鐵已經很久沒有更博了。自從考完noip後老鐵一蹶不振,從此走上心理陰影無限大,吾將上下而求索的道路。又去石家莊聽課 並不能聽懂 於是自己學一學一些奇怪的演算法。題目描述 檢查乙個如下的6 x 6的跳棋棋盤,有六個棋子被放置在棋盤上,使得每行 每列有且只有乙個,每條對角線 包括兩條主對角線的所有平行...
演算法 位運算 與 n皇后問題
問題a 返回n皇后擺法有多少種?遞迴函式,維護三個變數和乙個常量 常量 upperlim 代表棋盤大小,末尾n個1,例如八皇后,00 011111111 變數 顯然,遞迴函式的跳出條件為,nowlim upperlim 其中每層遞迴函式,可以通過位運算快速找到可以擺放的位置。pos upperlim...