八皇后問題

一、八皇后問題

八皇后問題,是一個古老而著名的問題,是回溯算法的典型案例。該問題是國際西洋棋棋手馬克斯·貝瑟爾於1848年提出:在8×8格的國際象棋上擺放八個皇后,使其不能互相攻擊,即任意兩個皇后都不能處於同一行、同一列或同一斜線上,問有多少種擺法。 高斯認爲有76種方案。1854年在柏林的象棋雜誌上不同的作者發表了40種不同的解,後來有人用圖論的方法解出92種結果。

這裏寫圖片描述

二、算法思路:

  首先我們分析一下問題的解,我們每取出一個皇后,放入一行,共有八種不同的放法,然後再放第二個皇后,同樣如果不考慮規則,還是有八种放法。
  於是我們可以用一個八叉樹來描述這個過程。從根節點開始,樹每增加一層,便是多放一個皇后,直到第8層(根節點爲0層),最後得到一個完全八叉樹。  
 
  我們先對問題解的結構做一個約定:
  用gEightQueen[i]來表示,在第i行,皇后放在了(i,gEightQueen[i])這個位置。

我們考慮條件:
一共有四個,不能同一行,不能同一列,不在同一左右對角線上。
同一行、同一列好解決,
左對角線是x座標和y座標的和不相等,右對角線是x-y不相等,有正負之分。

三、代碼,主要用到了遞歸和回溯,註釋非常清楚

#include<iostream>
using namespace std;
int num=0;
static int gEightQueen[8] = { 0 }, gCount = 0;//用gEightQueen[i]來表示,在第i行,皇后放在了gEightQueen[i]這個位置。
void print()//輸出每一種情況下棋盤中皇后的擺放情況
{
    cout<<"No."<<num<<endl;
    for (int i = 0; i < 8; i++)
    {   
        int inner;
        for (inner = 0; inner < gEightQueen[i]; inner++)
        {
            cout << "0 ";
        }
        cout <<"# ";
        for (inner = gEightQueen[i] + 1; inner < 8; inner++)
        {
            cout << "0 ";
        }
        cout << endl;
    }

    cout << "==========================\n";
}

int check_pos_valid(int loop, int value)//檢查是否存在有多個皇后在同一行/列/對角線的情況,loop和value爲要檢查的位置 
{//index和data是皇后的行和列  loop是檢查位置的行,value是檢查位置的列 
    int index;
    int data;
    for (index = 0; index < loop; index++)//檢查index以上所有行的皇后,是否跟當前位置衝突 
    {
        data = gEightQueen[index];//初始設爲0,行列範圍是1-8
        if (value == data)
            return 0;
        if ((index + data) == (loop + value))
            return 0;
        if ((index - data) == (loop - value))
            return 0;
    }
    return 1;
}

void eight_queen(int index)//index是當前檢查行 
{
    int value;
    for (value = 0; value < 8; value++)//檢查index行上所有列 
    {
        if (check_pos_valid(index, value))//如果index行上有不會導致衝突的列座標,就放一個皇后 
        {
            gEightQueen[index] = value;
            if (7 == index)//如果放到第8行,就計數、打印,函數結束 。
            {//這裏就是回溯,在每一個節點處向下把所有的可能做完了才向上返回
                gCount++, num++,print();
                //gEightQueen[index] = 0;  這兩句是遞歸結束後,把數據清零 
                return;
            }
            eight_queen(index + 1);//沒到第八行,就檢查下一行 
            //gEightQueen[index] = 0; 遞歸下層返回時,把數據清零,這裏刪掉沒關係是因爲每次使用都是賦值覆蓋後,沒有預設它本來是什麼值 
        }
    }
}

int main(int argc, char*argv[])
{
    eight_queen(0);
    cout << "total=" << gCount << endl;
    return 0;
}

四、運行結果
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章