數據結構裏面有個比較著名的八皇后問題,其解決方式倒有很多種,而搜索樹又算是一個人工智能方面的入門的思想和手段了。下面就說下如何用搜索樹來解決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的時候就掛了....
當然皇后問題也不止這一種解決方法,還有諸如貪心算法等可以解決,也可以說是各取所需吧。