利用搜索樹來解決N皇后問題

 

數據結構裏面有個比較著名的八皇后問題,其解決方式倒有很多種,而搜索樹又算是一個人工智能方面的入門的思想和手段了。下面就說下如何用搜索樹來解決N皇后問題

以四皇后問題爲例,如圖:

 

 


在第零層,只有一個根節點

在第一層,有四個節點符合符合條件,故根節點有四個子節點

在第二層,各個子節點又具有不同的節點,所以,這棵樹繼續往下生長,直至長到第4層,也就是說找到了解,那麼第四層的節點就是這個四皇后問題的解了。(注意,這裏可以採用深度優先搜索與廣度優先搜索,各有利弊)

同樣的理論和方法,利用這個搜索樹可以實現尋找出所有形式的皇后問題的解,下面就附上C++的源代碼

 

#include <list>
#include <iostream>

const int SIZE = 8; //這個是皇后問題的個數
const char Queue = '*'; //表示該點已經存在皇后了
const char Valid = ' '; //表示該點還可以放置皇后
const char Invalid = '_'; //表示該點因不符合條件而不能放置皇后

//定義搜索樹的節點,這個節點包含節點的高度及盤面狀態(利用數組來保存)
typedef struct _QueueNode
{
    char map[SIZE][SIZE];
    int height;
} QueueNode;

//根據給定的位置來更新相應節點中的盤面信息
void updateMapByPosition(QueueNode *node, int position)
{
    //此更新橫行
    for (int i = 0; i != SIZE; i++)
    {
        if (i != position)
        {
            node->map[node->height][i] = Invalid;
        }
    }
    //更新豎行
    for (int i = 0; i != SIZE; i++)
    {
        if (i != node->height)
        {
            node->map[i][position] = Invalid;
        }
    }
    //更新斜行
    for (int i = 0; i != SIZE; i++)
    {
        for (int j = 0; j != SIZE; j++)
        {
            if (((i + j) == (position + node->height)) && node->map[i][j] == Valid)
            {
                node->map[i][j] = Invalid;
            }
            if (((i - j) == (node->height - position)) && node->map[i][j] == Valid)
            {
                node->map[i][j] = Invalid;
            }
        }
    }
}
//這個用來搜索子節點並更新queueList
void collectNextNodes(std::list<QueueNode*> &queueList, QueueNode *node)
{
    QueueNode *tempNode = NULL;
    if (node->height >= SIZE)
    {
        return;
    }

    for (int i = 0; i != SIZE; i++)
    {
        if (node->map[node->height][i] == Valid)
        {
            tempNode = new QueueNode;

            for (int j = 0; j != SIZE; j++)
            {
                for (int k = 0; k != SIZE; k++)
                {
                    tempNode->map[j][k] = node->map[j][k];
                }
            }
            tempNode->height = node->height;
            tempNode->map[tempNode->height][i] = Queue;
            updateMapByPosition(tempNode, i);
            tempNode->height++;
            queueList.push_back(tempNode);
        }
    }
}

int main()
{
    std::list<QueueNode*> queueList; //存儲中間盤面的節點
    std::list<QueueNode*> solution;  //存儲符合皇后問題的節點
    queueList.clear();
    solution.clear();
    QueueNode *node = new QueueNode;    //創建初始的空盤面節點,其高度爲1
    for (int j = 0; j != SIZE; j++)
    {
        for (int k = 0; k != SIZE; k++)
        {
            node->map[j][k] = Valid;
        }
    }
    node->height = 0;
    queueList.push_back(node);
    while (!queueList.empty())
    {
        QueueNode *tempNode = queueList.front();
        queueList.pop_front();
        collectNextNodes(queueList, tempNode);
        //如果高度等於SIZE(即得到解),則入到solution隊列中,否則刪除掉,釋放資源
        if (tempNode->height == SIZE)
        {
            solution.push_back(tempNode);
        }
        else
        {
            delete tempNode;
        }
    }
    //這裏作爲一個數據鑑別,表明一共有多少個符合條件的答案
    std::cout << solution.size()<<std::endl;

    //這裏只是作爲一個展示打印出第一個而已,也可以以別的方式處理
    node = solution.front();
    if(node != NULL)
    {
        for (int j = 0; j != SIZE; j++)
        {
            for (int k = 0; k != SIZE; k++)
            {
                std::cout.put(node->map[j][k]).put(' ');
            }
            std::cout << std::endl;
        }
    }
}

 

 賦予SIZE不同的數值就可以得出不同的解,這裏我只是打印出了第一個解,其餘的解都已經存在於solution中,可以自己去處理下

皇后問題的解依照其問題的大小而不同,而隨着數據的增大,其空間複雜度幾乎就是呈指數形式的增長,在我的電腦上跑下SIZE=15的時候就掛了....

當然皇后問題也不止這一種解決方法,還有諸如貪心算法等可以解決,也可以說是各取所需吧。

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