西洋棋中的 八皇后問題

閱讀時間約 10 分鐘

前言

最近剛好看到這題,以前沒學好的題目,重讀了一次,順手做個筆記幫助記憶,也分享給有需要或有興趣的讀者。內容枯燥,適合睡前閱讀。

我只略懂表面,歡迎高手路人留言指導,教學相長。

問題描述

八皇后問題是一個經典的計算機科學問題,目標是:在 8 × 8 的西洋棋棋盤上放置 8 個皇后,且任兩個皇后都不能在同一行,或同一列,或同一對角線上。這意味著棋盤上任何兩個皇后都不能互相攻擊,彼此相安無事。這題一共有 92 種不同的解法。

八皇后問題還可以擴展到更大的棋盤和更多的皇后,稱之為 N皇后問題 (N-Queens Problem),可用於測試和理解演算法的性能,Edsger Dijkstra 也曾用這問題來展示結構化編程 (structured programming) 的能力。

八皇后問題也曾出現在 1990 年代初期的著名電子遊戲《第七訪客》中。

舉例

為方便製圖與解說,下面以四皇后 (4x4棋盤,4個皇后) 為例。圖中四個皇后的位置,彼此不在攻擊範圍,所以算是其中一組解。

四皇后問題的其中一組解,4位皇后相安無事

四皇后問題的其中一組解,4位皇后相安無事

而下圖中,有兩位皇后位於彼此的對角線上,處於攻擊位置,因此不是這題的解。

以紅色衰臉表示。

兩個紅后在對角線上,可互相攻擊,不能當作解

兩個紅后在對角線上,可互相攻擊,不能當作解

解的數量

四皇后有 2 組解,八皇后有 92 組解。

下表直接列出 N皇后問題中,不同的 N 分別有多少組解。可以注意到,若且唯若 N = 1 或 N ≥ 4, N皇后問題有解。即 N = 2 或 N = 3 時,此題無解。

The Number of Solutions for the N-Queens Problem

The Number of Solutions for the N-Queens Problem

解題方法

暴力解

窮舉所有皇后的擺法,然後逐一檢查是否為解。

然而全部有 C N2 取 N 種不同的擺法,當 N = 4 已有 1820 種擺法,而當 N = 8 則暴增到 4,426,165,368 種擺法,如何有邏輯的窮舉,是這題的關鍵。其實也非常簡單,下面繼續以四皇后問題為例來說明。

*由於講容易混淆,所以之後都用 rowcol 取代:row 表示橫向 (左右),col 表示縱向 (上下,即 column 之意)。

在大小為 4x4 的棋盤 ,擺放 4 個皇后

在大小為 4x4 的棋盤 ,擺放 4 個皇后

首先,直覺想法是:

  • 第 1 個皇后,有 16 個位子可以選
  • 第 2 個皇后,剩 15 個位子可以選
  • 第 3 個皇后,剩 14 個位子可以選
  • 第 4 個皇后,剩 13 個位子可以選

但其中有一堆重複的擺法,還有一堆不符合題目要求的擺法,這樣解題非常浪費算力。

稍作優化

  1. 根據題目要求,任兩個皇后不能擺在同個 row 上,所以簡化為在每個 row 擺 1 個皇后
  • row 0 擺 1 個皇后,有 4 個位子可選 (column 0、1、2、3)
  • row 1 擺 1 個皇后,有 4 個位子可選
  • row 2 擺 1 個皇后,有 4 個位子可選
  • row 3 擺 1 個皇后,有 4 個位子可選

如下圖, decision tree 大概長這樣。

row 0 有 4 個位子可選,不論選哪,row 1 也會有 4 個位子可選,依此類推

row 0 有 4 個位子可選,不論選哪,row 1 也會有 4 個位子可選,依此類推

  1. 根據題目要求,任兩個皇后也不能擺在同個 column 上,所以再簡化為在每個 row 擺 1 個皇后,且 column 不能重複
  • row 0 擺 1 個皇后,有 4 個位子可選
  • row 1 擺 1 個皇后,剩 3 個位子可選
  • row 2 擺 1 個皇后,剩 2 個位子可選
  • row 3 擺 1 個皇后,剩 1 個位子可選

如圖,整個 decision tree 變小許多。

如紅叉所示,如果在 row 0 時選擇了 col 0 擺放皇后,row 1 就不能將皇后擺放在 col 0,依此類推

如紅叉所示,如果在 row 0 時選擇了 col 0 擺放皇后,row 1 就不能將皇后擺放在 col 0,依此類推

  1. 根據題目要求,任兩個皇后除了不能擺在相同 row或相同 column或彼此對角線上
擺了一個皇后後,她的 row、column、對角線上,不能再出現另位皇后

擺了一個皇后後,她的 row、column、對角線上,不能再出現另位皇后

因此 decision tree 可以再縮小一些,很好理解,就不畫出來了。

總結

完整步驟:

  1. 從 row 0 到 row 3,依序選擇 1 個 col 位子,擺放 1 個皇后
  2. 選擇 col 時,從 col 0 開始檢查是否在其他皇后的 col 或對角線上。若無,則把皇后放下去。若有,則檢查下個位子, col 1,直到 col 3
  3. 若 col 0~3 都不能擺,則回到前一個 row,按步驟 1、步驟 2 幫皇后換個位子。
  4. 直到 row 0 到 row 3 都擺了皇后,即找到一組解
  5. (optional) 若想找到其他解,就跳到步驟 3。持續到最後就能檢查完整個 decision tree

不好描述,建議搭配程式一起看。

可以把 decision tree 當作舊文 混亂的約會行程,竟是學妹給的智力測驗 裡的有向無環圖 (DAG),概念就完全一樣了!

從 decision tree 的起點往下走,直到最深處,然後回到上一層,選擇另條路再走到最深處,邊走邊檢查 row 和 col 是否符題目要求。


程式實作

程式碼

使用 C++

n_queens.cpp

class NQueens {
public:
std::vector<std::vector<std::string>> FindSolutions(int n) {
std::vector<std::vector<std::string>> ret;
std::vector<int> temp(n);
Backtrack(ret, temp, n, 0, 0);
return ret;
}

void Backtrack(std::vector<std::vector<std::string>>& ret,
std::vector<int> temp, int n, int row, int col) {
if (row == n) Save(ret, temp);
if (row == n || col == n) return;
if (IsSafe(temp, row, col)) {
temp[row] = col;
Backtrack(ret, temp, n, row+1, 0);
}
Backtrack(ret, temp, n, row, col+1);
}

bool IsSafe(std::vector<int>& temp, int row, int col) {
for (int i = 0; i < row; ++i) {
if (temp[i] == col) return false;
if (std::abs(temp[i]-col) == std::abs(i-row)) return false;
}
return true;
}

void Save(std::vector<std::vector<std::string>>& ret,
std::vector<int>& temp) {
auto n = temp.size();
std::vector<std::string> ans(n, std::string(n, '-'));
for (std::size_t i = 0; i < temp.size(); ++i) {
ans[i][temp[i]] = 'Q';
}
ret.emplace_back(std::move(ans));
}
};

int main(int argc, char *argv[]) {
int n = std::atoi(argv[1]);
int count = 1;
auto solutions = NQueens{}.FindSolutions(n);

// print solutions
for (const auto& sol : solutions) {
std::cout << "solution: " << count++ << std::endl;
for (const auto& s : sol) {
std::cout << s << std::endl;
}
std::cout << std::endl;
}
return EXIT_SUCCESS;
}

看不懂很正常,我直接從個人的題庫筆記 copy 過來,有些不相關的 code。

編譯

g++ n_queens.cpp -o n_queens

執行結果

四皇后

$ ./n_queen.out 4

solution: 1
-Q--
---Q
Q---
--Q-

solution: 2
--Q-
Q---
---Q
-Q--

八皇后,看起來 92 種解法都有找到,但沒驗證過。

$ ./n_queen.out 8

solution: 1
Q-------
----Q---
-------Q
-----Q--
--Q-----
------Q-
-Q------
---Q----

solution: 2
Q-------
-----Q--
-------Q
--Q-----
------Q-
---Q----
-Q------
----Q---

()

solution: 92
-------Q
---Q----
Q-------
--Q-----
-----Q--
-Q------
------Q-
----Q---

結語

小時不讀書,長大當社畜,真是悔不當初啊~

    62會員
    21內容數
    個人網誌啦~ 內容包含但不限於學習筆記、心情抒發、火星廢文...
    留言0
    查看全部
    發表第一個留言支持創作者!
    JN的沙龍 的其他內容
    看著認真、認命上班的人越來越多,感觸良多,​我就提醒一句, 「不要瞎忙,以終為始,」 「begin with the end in mind」 懂的就懂。
    當主管突然交代一堆工作時,我們通常會先估算各項工作需要的時間,然後按部就班執行。但當主管為各項工作設定了 deadline,我們對於如何安排一個有效率的排程,往往百思不得其解。這類問題變化非常多,本篇文章將以其中一種常見的情境來分享解題思路...
    前陣子看到有人在討論徵友,讓我想起大學時的學妹,小香,清新脫俗,香氣四溢,每天排隊給她帶三餐的工具男多到「罄竹難書」,而我也是其一。我相信有試有機會,畢竟我爸開保時捷,我媽開法拉利,我開玩笑...
    看著認真、認命上班的人越來越多,感觸良多,​我就提醒一句, 「不要瞎忙,以終為始,」 「begin with the end in mind」 懂的就懂。
    當主管突然交代一堆工作時,我們通常會先估算各項工作需要的時間,然後按部就班執行。但當主管為各項工作設定了 deadline,我們對於如何安排一個有效率的排程,往往百思不得其解。這類問題變化非常多,本篇文章將以其中一種常見的情境來分享解題思路...
    前陣子看到有人在討論徵友,讓我想起大學時的學妹,小香,清新脫俗,香氣四溢,每天排隊給她帶三餐的工具男多到「罄竹難書」,而我也是其一。我相信有試有機會,畢竟我爸開保時捷,我媽開法拉利,我開玩笑...
    你可能也想看
    Google News 追蹤
    Thumbnail
    這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
    Thumbnail
    美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
    Thumbnail
    Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
    Thumbnail
    歡迎各位踴躍報名 報名連結 比賽資訊 地點:台中市霧峰區萊園路57巷2號(南天宮)時間:12/30 中午~下午12:45開始報到 1:00開始比賽 規則:參照fide一般西洋棋規則。須摸子走子;餘剩時間10分內需同手按鍾,犯規2次判輸。 賽制:5輪15d10組別:公開組,任何人皆可參加 獎
    Thumbnail
    介紹一下關於王兵殘局的觀念。 當雙方僅剩下王與兵時便是王兵殘局,而在殘局中兵的升變是至關重要的。 在兵數量相當的王兵殘局中,分散的兵通常會比結成一團的兵更容易出現通路兵,進而更容易升變,因為王兵殘局中國王無暇顧及兩處的士兵。 在王兵殘局中,多2只兵是必勝的。 而若交換到最後只多1
    Thumbnail
    類型:棋藝 教學科目:西洋棋 老師學歷:大學 西洋棋暑期體驗活動報名表單連結 https://forms.gle/yoJ4s4kEixsMu4Xq9 老師經歷: 曾獲台中市長盃高中組季軍 台北市西洋棋比賽新人組冠軍 高雄市中級乙組亞軍 曾進入國手選拔賽複賽 台中市春季積分
    Thumbnail
    錫塔所研發的棋盤一共64個格子,到了第64個格子的時候,需要放的麥子數量就是2的(64-1)次方,想知道最終需要多少麥子的話可以自己用計算機計算一下。不過要注意的是,錫塔所得到的麥子並非只是2的63次方,而是64個格子的麥子的總和,因此,這國家的國王可真算是倒霉了,遇到一個數學高手。 看完這個故事之
    Thumbnail
    可不知從哪一刻起,喧鬧的人們突然安靜下來。因為往第16個方格上放米粒時,就需要拿出1公斤的大米,而到了第20格時,則需要滿滿一手推車的米。在這個時候,國王和大臣們發覺即使傾全國所有的麥子,好像也不足以放滿棋盤的64格,他們只能是驚訝地張大了嘴。 相信國王最後的處境會變得十分尷尬,因為他國家的麥子根本
    Thumbnail
    麥子被拉來後,糧食大臣一粒一粒地填了起來。一粒、兩粒、四粒、八粒……一開始,前面的幾個方格很快就被填滿,而此時還沒有用完一小碗麥子。但是慢慢地,所用的麥子開始明顯多了起來,三十二粒、六十四粒、一百二十八粒、二百五十六粒、五百一十二粒、一千零二十四粒…… 隨著放置麥粒的方格不斷增多,搬運麥粒的工具也從
    Thumbnail
    在古印度的時候,有一個名叫錫塔的大臣,他十分聰明,發明了一種棋子,令國王百玩不厭,於是便決定重賞錫塔。國王問錫塔想要什麼獎賞,他說:「陛下,我只想要一點點麥子。請您讓人把麥子放在我發明的棋盤的六十四個格子內,第一格放一粒,第二格放二粒,第三格放四粒,第四格放八粒,第五格放十六粒……照這樣放下去,每格
    Thumbnail
    第一步也是最重要的一步,無預警Netflix的年中出現一步吸引人的影集,后翼棄兵,怎知世界上還有這樣的古老桌遊西洋棋,跟電玩、桌遊、各種腦力遊戲不一樣,可是有那麼點熟悉感,看起來不就是中國象棋麼?可是那立體的形象,黑白的棋盤,國王、王后、主教、棋士、城堡、小兵抽象的京士頓造型,加上精采的主人翁哈
    Thumbnail
    剛看完一部片子,《女僕與西洋棋》,很簡單的一部片,卻帶出滿多感覺。 海倫每天起床盤好髮髻,著裝完畢後草草吃完簡單的早餐,騎上單車到附近的一間旅館工作,她是旅館的清潔打掃工,娜塔莉是常和她搭檔的工作伙伴,常和她談起想去巴黎高級旅館工作的夢想,反問海倫:「妳都不想的嗎?」海倫回答:「我從不想這些的。」
    Thumbnail
    這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
    Thumbnail
    美國總統大選只剩下三天, 我們觀察一整週民調與金融市場的變化(包含賭局), 到本週五下午3:00前為止, 誰是美國總統幾乎大概可以猜到60-70%的機率, 本篇文章就是以大選結局為主軸來討論近期甚至到未來四年美股可能的改變
    Thumbnail
    Faker昨天真的太扯了,中國主播王多多點評的話更是精妙,分享給各位 王多多的點評 「Faker是我們的處境,他是LPL永遠繞不開的一個人和話題,所以我們特別渴望在決賽跟他相遇,去直面我們的處境。 我們曾經稱他為最高的山,最長的河,以為山海就是盡頭,可是Faker用他28歲的年齡...
    Thumbnail
    歡迎各位踴躍報名 報名連結 比賽資訊 地點:台中市霧峰區萊園路57巷2號(南天宮)時間:12/30 中午~下午12:45開始報到 1:00開始比賽 規則:參照fide一般西洋棋規則。須摸子走子;餘剩時間10分內需同手按鍾,犯規2次判輸。 賽制:5輪15d10組別:公開組,任何人皆可參加 獎
    Thumbnail
    介紹一下關於王兵殘局的觀念。 當雙方僅剩下王與兵時便是王兵殘局,而在殘局中兵的升變是至關重要的。 在兵數量相當的王兵殘局中,分散的兵通常會比結成一團的兵更容易出現通路兵,進而更容易升變,因為王兵殘局中國王無暇顧及兩處的士兵。 在王兵殘局中,多2只兵是必勝的。 而若交換到最後只多1
    Thumbnail
    類型:棋藝 教學科目:西洋棋 老師學歷:大學 西洋棋暑期體驗活動報名表單連結 https://forms.gle/yoJ4s4kEixsMu4Xq9 老師經歷: 曾獲台中市長盃高中組季軍 台北市西洋棋比賽新人組冠軍 高雄市中級乙組亞軍 曾進入國手選拔賽複賽 台中市春季積分
    Thumbnail
    錫塔所研發的棋盤一共64個格子,到了第64個格子的時候,需要放的麥子數量就是2的(64-1)次方,想知道最終需要多少麥子的話可以自己用計算機計算一下。不過要注意的是,錫塔所得到的麥子並非只是2的63次方,而是64個格子的麥子的總和,因此,這國家的國王可真算是倒霉了,遇到一個數學高手。 看完這個故事之
    Thumbnail
    可不知從哪一刻起,喧鬧的人們突然安靜下來。因為往第16個方格上放米粒時,就需要拿出1公斤的大米,而到了第20格時,則需要滿滿一手推車的米。在這個時候,國王和大臣們發覺即使傾全國所有的麥子,好像也不足以放滿棋盤的64格,他們只能是驚訝地張大了嘴。 相信國王最後的處境會變得十分尷尬,因為他國家的麥子根本
    Thumbnail
    麥子被拉來後,糧食大臣一粒一粒地填了起來。一粒、兩粒、四粒、八粒……一開始,前面的幾個方格很快就被填滿,而此時還沒有用完一小碗麥子。但是慢慢地,所用的麥子開始明顯多了起來,三十二粒、六十四粒、一百二十八粒、二百五十六粒、五百一十二粒、一千零二十四粒…… 隨著放置麥粒的方格不斷增多,搬運麥粒的工具也從
    Thumbnail
    在古印度的時候,有一個名叫錫塔的大臣,他十分聰明,發明了一種棋子,令國王百玩不厭,於是便決定重賞錫塔。國王問錫塔想要什麼獎賞,他說:「陛下,我只想要一點點麥子。請您讓人把麥子放在我發明的棋盤的六十四個格子內,第一格放一粒,第二格放二粒,第三格放四粒,第四格放八粒,第五格放十六粒……照這樣放下去,每格
    Thumbnail
    第一步也是最重要的一步,無預警Netflix的年中出現一步吸引人的影集,后翼棄兵,怎知世界上還有這樣的古老桌遊西洋棋,跟電玩、桌遊、各種腦力遊戲不一樣,可是有那麼點熟悉感,看起來不就是中國象棋麼?可是那立體的形象,黑白的棋盤,國王、王后、主教、棋士、城堡、小兵抽象的京士頓造型,加上精采的主人翁哈
    Thumbnail
    剛看完一部片子,《女僕與西洋棋》,很簡單的一部片,卻帶出滿多感覺。 海倫每天起床盤好髮髻,著裝完畢後草草吃完簡單的早餐,騎上單車到附近的一間旅館工作,她是旅館的清潔打掃工,娜塔莉是常和她搭檔的工作伙伴,常和她談起想去巴黎高級旅館工作的夢想,反問海倫:「妳都不想的嗎?」海倫回答:「我從不想這些的。」