一道算法題-八皇后問題(C++實現)


八皇后問題

一、題意解析

  國際象棋中的皇后,可以橫向、縱向、斜向移動。如何在一個8X8的棋盤上放置8個皇后,使得任意兩個皇后都不在同一條橫線、豎線、斜線方向上?八皇后問題是一個古老的問題,於1848年由一位國際象棋棋手提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,如何求解?以高斯為代表的許多數學家先后研究過這個問題。后來,當計算機問世,通過計算機程序的運算可以輕松解出這個問題。

二、如何解決八皇后問題?

  所謂遞歸回溯,本質上是一種枚舉法。這種方法從棋盤的第一行開始嘗試擺放第一個皇后,擺放成功后,遞歸一層,再遵循規則在棋盤第二行來擺放第二個皇后。如果當前位置無法擺放,則向右移動一格再次嘗試,如果擺放成功,則繼續遞歸一層,擺放第三個皇后......

  如果某一層看遍了所有格子,都無法成功擺放,則回溯到上一個皇后,讓上一個皇后右移一格,再進行遞歸。如果八個皇后都擺放完畢且符合規則,那么就得到了其中一種正確的解法。說起來有些抽象,我們來看一看遞歸回溯的詳細過程。

  1.第一層遞歸,嘗試在第一行擺放第一個皇后

  2.第二層遞歸,嘗試在第二行擺放第二個皇后(前兩格被第一個皇后封鎖,只能落在第三格):

  3.第三層遞歸,嘗試在第三行擺放第三個皇后(前四格被第一第二個皇后封鎖,只能落在第五格):

  4.第四層遞歸,嘗試在第四行擺放第四個皇后(第一格被第二個皇后封鎖,只能落在第二格):

  5.第五層遞歸,嘗試在第五行擺放第五個皇后(前三格被前面的皇后封鎖,只能落在第四格):

  6.由於所有格子都“綠了”,第六行已經沒辦法擺放皇后,於是進行回溯,重新擺放第五個皇后第八格。:

  7.第六行仍然沒有辦法擺放皇后,第五行也已經嘗試遍了,於是回溯到第四行,重新擺放第四個皇后第七格。:

  8.繼續擺放第五個皇后,以此類推......

三、八皇后問題的代碼實現

  解決八皇后問題,可以分為兩個層面:

1.找出第一種正確擺放方式,也就是深度優先遍歷。

2.找出全部的正確擺放方式,也就是廣度優先遍歷。

 我們本篇只介紹如何找出第一種正確擺放方式。具體代碼如下:

  1 //"八皇后問題回溯實現"
  2 #include <iostream>
  3 using namespace std;
  4 const int ArSize = 8;//這個數等於幾,就是幾皇后。
  5 int num = 0;
  6 void solve(bool arr[ArSize][ArSize], int row);
  7 bool check(bool arr[ArSize][ArSize], int row, int column);
  8 void outPut(bool arr[ArSize][ArSize]);
  9 
 10 int main()
 11 {
 12     bool chessboard[ArSize][ArSize];
 13     // 數組初始化
 14     for (auto &i : chessboard)
 15     {
 16         for (auto &j : i)
 17         {
 18             j = false;
 19         }
 20     }
 21     solve(chessboard, 0);
 22     cout << "八皇后問題共有" << num << "種解!" << endl;
 23     system("pause");
 24     return 0;
 25 }
 26 // 回溯法
 27 void solve(bool arr[ArSize][ArSize], int row)
 28 {
 29     for (int column = 0; column < ArSize; ++column)
 30     {
 31         arr[row][column] = true;
 32         if (check(arr, row, column))
 33         {
 34             if (row + 1 == ArSize)
 35             {
 36                 outPut(arr);
 37             }
 38             else
 39             {
 40                 solve(arr, row + 1);
 41             }
 42         }
 43         arr[row][column] = false;
 44     }
 45 }
 46 // 判斷皇后的落點是否合規
 47 bool check(bool arr[ArSize][ArSize], int row, int column)
 48 {
 49     if (row == 0)
 50     {
 51         return true;
 52     }
 53     int i, j;
 54     // 判斷縱向是否有沖突
 55     for (i = 0; i < row; ++i)
 56     {
 57         if (arr[i][column])
 58         {
 59             return false;
 60         }
 61     }
 62     i = row - 1;
 63     j = column - 1;
 64     // 判斷正斜對角線是否有沖突
 65     while (i >= 0 && j >= 0)
 66     {
 67         if (arr[i][j])
 68         {
 69             return false;
 70         }
 71         --i;
 72         --j;
 73     }
 74     i = row - 1;
 75     j = column + 1;
 76     // 判斷負斜對角線是否有沖突
 77     while (i >= 0 && j <= ArSize - 1)
 78     {
 79         if (arr[i][j])
 80         {
 81             return false;
 82         }
 83         --i;
 84         ++j;
 85     }
 86     return true;
 87 }
 88 // 打印每種正確的解法
 89 void outPut(bool arr[ArSize][ArSize])
 90 {
 91     ++num;
 92     cout << "**********************" << num << "*********************" << endl;
 93     for (int i = 0; i < ArSize; ++i)
 94     {
 95         for (int j = 0; j < ArSize; ++j)
 96         {
 97             cout << arr[i][j] << " ";
 98         }
 99         cout << endl;
100     }
101     cout << "*********************************************" << endl;
102 }

  輸出結果的部分截圖如下:

 

 

參考資料:

http://www.cnblogs.com/yonggandefeng/p/6275861.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM