n皇后問題--分支限界法
阿新 • • 發佈:2018-12-14
問題描述
八皇后問題是一個古老而著名的問題,它是回溯演算法的典型例題,現在用分支限界的演算法來解決這個問題。該問題是十九世紀德國著名數學家高斯於1850年提出的:在8行8列的國際象棋棋盤上擺放著 八個皇后。若兩個皇后位於同一行、同一列或同一對角線上,則稱為它們為互相攻擊。現在要求使這N個皇后不能相互攻擊,即任意兩個皇后都不能處於同一行、同一列或同一對角線上,問有多少種擺法。
在分支限界法中,每一個活結點只有一次機會成為擴充套件節點。活結點一旦成為擴充套件節點,就一次性產出所有兒子節點。在這些所有的兒子節點中,導致不可行解或導致非最優解的兒子節點被捨棄,滿足條件的兒子結點被加入到活結點表中。此後,從活結點表中取下一個結點成為當前擴充套件節點,並重覆上述結點擴充套件過程。這個過程一直持續到我們找到所需的解或者是活性表為空為止。
演算法模板
定義根節點t0為初始化擴充套件節點
根節點t0入隊
while(隊不空)
{
出隊 --t;
for (j = r0; j < rn; ++j)
{
對t利用規則j發展新節點tj;
利用限界函式判斷tj是否可行;
if (可行)
{
若是目標解,找到結果,return
否則,進隊
}
}
}
#include <iostream> #include <queue> using namespace std; class Node { public: Node(int n) : t(0), n(n) { pos = new int[n + 1]; for (int i = 0; i <= n; ++i) { pos[i] = 0; } } Node(const Node& other) { t = other.t; n = other.n; pos = new int[other.n + 1]; for (int i = 0; i <= n; ++i) { pos[i] = other.pos[i]; } } ~Node() { if (pos != NULL) { delete[] pos; pos = NULL; } } bool check(int next); int t;//當前已經放置了多少個皇后 int n;//需要放置多少個皇后 int *pos; //指向當前已放好的皇后位置,pos[1]代表第1個皇后所放的列數,所放的行數為1,這樣設定可以不用檢查行是否相等 }; bool Node::check(int next) { int i; //表示已經已經放置皇后的行 for (i = 1; i <= t; ++i) { int j = pos[i]; //代表已經放置的皇后的列 //同列 if (j == next) { return false; } //右上角到左下角的對角線 if ((next - j) == (i - 1 - t)) { return false; } //左上角到右下角的對角線 if ((next - j) == (t + 1 - i)) { return false; } } return true; } class Queen { public: Queen(int x) : n(x), ansNum(0){} int QueenArrange(); //排列皇后的方式 private: int n; //皇后數量 int ansNum; //n皇后解的數量 }; int Queen::QueenArrange() { queue<Node> q; Node f(n); q.push(f); while (!q.empty()) { Node x = q.front(); q.pop(); if (x.t == n) { ++ansNum; } //一次性將當前節點的所有擴充套件節點考慮完,符合條件的插入佇列 for (int i = 1; i <= n; ++i) { //利用剪枝函式,將不符合條件的分支切掉 if (x.check(i)) { Node child(x); ++child.t; child.pos[child.t] = i; //記錄位置 q.push(child); } } } return ansNum; } int main() { int n = 8; Queen queen(8); cout << queen.QueenArrange() << endl; }