重新開始戰鬥17 程式設計之美 八皇后問題

2021-06-21 09:31:01 字數 1660 閱讀 1751

申明:

八皇后問題沒有被《程式設計之美》收錄,和《重新開始戰鬥16-程式設計之美-判斷鍊錶是否有環》一樣,筆者也在面試時多次遇到這樣的問題,因此在這裡和大家分享。

八皇后遊戲的說明:

問題的提出:八皇后是個古老而有趣的遊戲,是由高斯於2023年首先提出的。要求在西洋棋的棋盤上放置八個皇后,使其不能相互攻擊,即任意兩個皇后不能處於棋盤的同一行、同一列和同一條對角線上。試問有多少種放法?

對於這個問題,對矩陣有點熟悉的同學會發現,在對角線上,(定義a00到ann為右對角線,an0到a0n為左對角線),若aij,apq在右對角線上,其座標

(i,j)

與(p,q)

滿足i-j=p-q

,而對於左對角線,則滿足

i+j=p+q。也許很多同學都可以找到這個關鍵點。然而更重要的是利用這個性質,進行高效簡單的編碼。

也就是說八皇后我們可以用樹去解決,其空間搜尋樹如下圖所示:

說明:圖中節點例如241表達的是3個皇后的位置:第一行第二列,第二行第四列和第三環第一列。採用回溯法,進行深度優先,不斷遍歷樹種節點,遇到不合適的節點進行回溯,直到達到葉子節點,則為乙個可行的擺法。下面先給出具體**,然後在行進說明:

int col[8],left[15],right[15];

int queen[8];

int n=0;

int sum=0;

void generate()

int h,i;

for(h=0;h<=7;h++)

if(col[h]&&left[n+h] && right[n-h+7])

queen[n]=h;

col[h]=false;

left[n+h]=false;

right[n-h+7]=false;

n+=1;

if(n==8)

sum++;

cout<

cout<

n--;

left[n+h]=true;

right[n-h+7]=true;

col[h]=true;

**說明:

col[8]陣列用以記錄8列中,每一列是否有皇后,例如col[6]=true,表示在第6列的某一行,有乙個皇后;

queen[8]陣列表示第i列的皇后所在的行。例如queen[2]=3,表示3行2列有乙個皇后;

n用於表示樹的層數;

sum用於累加路徑條數,即可以擺放的擺法數目。

**的核心——left[15]與right[15]陣列

left[15]陣列:表示左對角線,正如上面的說明,兩個點在做對角線上,其座標之和一樣,那麼left[i]表示,所有(x,y)點,只要滿足x+y=i是否放有皇后的情況。例如在深度優先檢索一條路徑的過程中,第3號皇后的位置為(4,3),此刻,一定標記left[4+3]=true,因此在對於第四號皇后,其位置不能為(3,4),因為3+4=7,(3,4)與(4,3)一定是出於左對角線上!!!在程式中加入這樣的檢索,就有點了貪心的思想在裡面!!!!當在遍歷到樹中的某一層,發下沒有可用的位置,說明該擺法不正確,因此立刻層層返回!!!

注意在返回的過程中,清空col,left,right等陣列,執行n—等操作。保證回到頂層時,各個記錄陣列的狀態彷彿「新的」一樣。

重新開始戰鬥03 程式設計之美 買書問題

問題描述 由於 哈利波特 系列相當暢銷,店長決定通過 活動來回饋讀者。上櫃的 哈利波特 瓶裝本系列中,一共有5卷。假設每一捲單獨銷售均需8歐元。如果讀者一次購買不同的兩卷,就可以扣除5 的費用,三卷更多。具體的折扣如下 本數 折扣 2 5 3 10 4 20 5 25 每本書只能享受一種折扣。例如買...

重新開始戰鬥05 程式設計之美 光影切割

問題描述 假設有乙個矩形區域,有若干條直線切割該區域,並且沒有一條直線與y軸平行,且不存在三條 以及3條以上 切割線相交於一點的情況。請問該矩形平面被分割成多少塊。分析 假設一塊矩形區域已經被切割成很多塊,那麼此時再增加一條切割線,新的切割線與其他切割線相交,且有m個交點。那麼新的切割線被分割成m ...

重新開始戰鬥04 程式設計之美 尋找ID問題

問題描述 乙個很大的列表 有10億多個數 這個列表中全是都是id號,正常狀態下每個id都會再列表中出現兩次 都是亂序 1.當有乙個id號丟失時,如何找到這個id號 2.當有兩個id號丟失時,如何找到這兩個id號。解法一 最直觀 申請乙個陣列,這個陣列和id列表一樣大,然後遍歷id列表,每遍歷乙個id...