C++八皇后問題

八皇后問題是由國際西洋棋棋手馬克斯·貝瑟爾于1848年提出的問題,是回溯算法的典型案例。

問題表述為:在8×8格的國際象棋上擺放8個皇后,使其不能互相攻擊,即任意兩個皇后都不能處于同一行、同一列或同一斜線上,問有多少種擺法。

像這樣的棋盤:

Queen

對棋盤行和列標號,可以使用 0~71~8,通過行數與列數進行加減計算,得到如下的內容:

Queen_leftLine.png
Queen_rightLine.png

行 - 列行 +列,可以清晰的看到具有很明顯的規律

行 - 列 ,紅線的方向,從左到右,從上到下的斜線,取值范圍 [-7 , 7],,共15個元素

-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7

行 +列,紅線的方向,從左到右,從下到上的斜線,取值范圍 [2 , 16][0 , 14] ,共15個元素

當列和行標號范圍 "1~8"
2,3,4,5,6,7,8,9,10,11,12,13,14,15,16

當列和行標號范圍 "0~7"
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14

解題方法 :

注 :此處使用行列的標號范圍 "1~8"

設置數組,判斷某位置是否處于一個安全的位置

1. 建立數組,并初始化

因為每種斜線最多有15種可能,行列最多只有8種可能

// 判斷左斜線
int r[16]   = { 0 };
// 判斷左斜線
int l[16]   = { 0 };
// 判斷列
int h[8] = { 0 };

例如: 取 x = 4, y = 5 位置,其左斜線 -1 ,右斜線 9 ,列 4

由于數組初始化為0,當填入一行皇后,需要進行占位,利用行列號來修改數組位置的值,修改為1

左斜線(x-y)取值范圍:[-7 , 7] ,因此在左斜線 x-y+8, 則對應數組 l[1] 到 l[15] 

右斜線(x+y)取值范圍:[2 , 16] ,因此在右斜線 x+y-1則對應數組 r[1] 到 r[15] 

例如:取 x = 4, y = 5 位置,4-5=-1,4+5=9 ,因此 l[7]=1、r[8]=1

2. 創建數組保存每種情況 , 并統計數量

// 符合條件的數量
int n = 0;
int que[8]  = { 0 };

創建一維數組,來存放每行皇后的位置,每個皇后的取值都不同,也就是取值由0到7

3. 創建函數,輸出保存數組的情況

void Print()
// 輸出
{
    cout << "第"<<n << "種:" ;
    for (int i = 0; i < 8; ++i)
    {
        cout << que[i] ;
    }
    cout << endl;
}

4. 設計遞歸函數

遞歸參數為行數

void Queen(int row = 0)
// 輸入行數
{
      // 函數出口
    if(row > 7)
    {
        n++;
        Print();
        return;
    }
    for (int i = 0; i < 8; ++i)
    {
        // 當一行到結尾,也沒有找到解法,結束,返回上一行,
        if(i>7)
        {
            return;
        }
        // 判斷是否符合條件
        if( !l[row-i+8] && !r[row+i-1] && !h[i])
        {
            // 符合條件保存該行的位置,并標記影響的斜線和列 
            que[row] = i;

            h[i] = 1;
            l[row-i+8] = 1;
            r[row+i-1]= 1;
            
            // 本行已找到,跳到下一行
            Queen(row+1);

            // 因為下一行沒有找到位置,結束函數,此行該位置不能得到的結果,因此清除之前設置的內容
            que[row] = 0;

            l[row-i+8] = 0;
            r[row+i-1]= 0;
            h[i] = 0;
        }
    }
}

例子:

#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;


// 符合條件的數量
int n = 0;
// 數組存放每行皇后的位置
int que[8]  = { 0 };

// 判斷左斜線
int l[16]   = { 0 };
// 判斷左斜線
int r[16]   = { 0 };
// 判斷列
int h[8] = { 0 };

void Print()
// 輸出
{
    cout << "第"<<n << "種:" ;
    for (int i = 0; i < 8; ++i)
    {
        cout << que[i] ;
    }
    cout << endl;
}

void Queen(int row = 0)
// 輸入行數
{
      // 每次遞歸結束的出口
    if(row > 7)
    {
        // 完成一次遞歸,結果加一,并打印,結束遞歸
        n++;
        Print();
        return;
    }
    for (int i = 0; i < 8; ++i)
    {
        // 當一行到結尾,也沒有找到解法,結束,返回上一行,
        if(i>7)
        {
            return;
        }
        // 判斷是否符合條件
        if( !l[row-i+8] && !r[row+i-1] && !h[i])
        {
            // 符合條件保存該行的位置,并標記影響的斜線和列 
            que[row] = i;

            h[i] = 1;
            l[row-i+8] = 1;
            r[row+i-1]= 1;
            
            // 本行已找到,跳到下一行
            Queen(row+1);

            // 因為下一行沒有找到位置,結束函數,此行該位置不能得到的結果,因此清除之前設置的內容
            que[row] = 0;

            l[row-i+8] = 0;
            r[row+i-1]= 0;
            h[i] = 0;
        }
    }
}
int main(int argv,char* argc[])
{
    Queen();
    cout << n <<endl;
    system("pause");
    return 0;
}

N皇后問題

通過八皇后可以推出N皇后的問題的解決方案

主要問題在于斜線的區間和數量

注:行列的標號范圍 "1~n"

當為N皇后,x+y的取值范圍 [2 , 2n] , x-y 取值范圍 [ 1-n , n-1 ] , 數量都為 2n-1

#include<iostream>
#include<cstdlib>

using namespace std;

template<int size>
class Queen
{
private:
    int num = 0;
    // 判斷左斜線
    int l[size*2] = { 0 };
    // 判斷左斜線
    int r[size*2] = { 0 };
    // 判斷列
    int h[size] = { 0 };
    // 數組
    int que[size] = { 0 };
public:
    Queen(){};
    ~Queen(){};
public:
    void check(int row = 0)
    {
        if(row >= size)
        {
            num++;
            Prints();
            return;
        }
        for (int i = 0; i < size; ++i)
        {
            if( !l[row-i+size] && !r[row+i-1] && !h[i])
            {
                que[row] = i;
                h[i] = 1;
                l[row-i+size] = 1;
                r[row+i-1]= 1;
                
                check(row+1);
                // 因為下一行沒有找到,因此此行該位置不能得到應有的結果,因此清空設置的內容

                que[row] = 0;
                l[row-i+size] = 0;
                r[row+i-1]= 0;
                h[i] = 0;
            }
        }
    }
    void Prints()
    // 輸出
    {
        cout << "第"<<num << "種:" ;
        for (int i = 0; i < size; ++i)
        {
            cout << que[i] ;
        }
        cout << endl;
    }
};

int main(int argc, char const *argv[])
{
    Queen<8> Sir;
    Sir.check();
    system("pause");
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容

  • 問題 八皇后問題是一個古老而著名的問題,是試探法的典型例題。該問題由19世紀數學家高斯1850年手工解決。原題為在...
    Stroman閱讀 739評論 0 1
  • 我今天好不容易上了一次課,然后數據結構老師給我們留大作業,喪心病狂,先解決一個叫八皇后的問題。 題目背景: 【問題...
    阿里高級軟件架構師閱讀 2,997評論 1 5
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學已經沒多少時間了。班主任說已經安排了三個家長分享經驗。 放學鈴聲...
    飄雪兒5閱讀 7,538評論 16 22
  • 今天感恩節哎,感謝一直在我身邊的親朋好友。感恩相遇!感恩不離不棄。 中午開了第一次的黨會,身份的轉變要...
    迷月閃星情閱讀 10,588評論 0 11
  • 可愛進取,孤獨成精。努力飛翔,天堂翱翔。戰爭美好,孤獨進取。膽大飛翔,成就輝煌。努力進取,遙望,和諧家園??蓯塾巫?..
    趙原野閱讀 2,748評論 1 1