n后問題-回溯法


問題描述:

  在n*n的棋盤上放置彼此不受攻擊的n個皇后。按國際象棋的規則,皇后可以與之處在同一行或者同一列或同一斜線上的棋子。

  n后問題等價於在n*n格的棋盤上放置n皇后,任何2個皇后不放在同一行或同一列的斜線上。

算法設計:

  |i-k|=|j-l|成立,就說明2個皇后在同一條斜線上。可以設計一個place函數,測試是否滿足這個條件。

  1 當i>n時,算法搜索至葉節點,得到一個新的n皇后互不攻擊放置方案,當前已找到的可行方案sum加1.

  2 當i<=n時,當前擴展結點Z是解空間中的內部結點。該結點有x[i]=1,2,3....n共n個兒子節點。

    對當前擴展結點Z的每個兒子節點,由place檢察其可行性。並以深度優先的方式遞歸地對可行子樹,或剪去不可行子樹。

算法描述: 

#include <iostream>
#include <cstdlib>
using namespace std;
class Queen{
    friend int nQueen(int);
private:
    bool Place(int k);
    void Backtrack(int t);
    int n,
        * x;
    long sum;
};
bool Queen::Place(int k)
{
    for(int j=1;j<k;j++)
        if((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))
            return false;
    return true;
}
void Queen::Backtrack(int t)
{
    if(t>n)
        sum++;
    else
        for(int i=1;i<=n;i++)
        {
            x[t] = i;
            if(Place(t))
                Backtrack(t+1);
        }
}
int nQueen(int n)
{
    Queen X;
    X.n = n;
    X.sum = 0;
    int *p = new int [n+1];
    for(int i=0;i<=n;i++)
        p[i] = 0;
    X.x = p;
    X.Backtrack(1);
    delete [] p;
    cout<<X.sum<<endl;
    return X.sum;
}
int main()
{
    nQueen(4);
    nQueen(2);
    nQueen(3);
    return 0;
}

執行結果:

迭代回溯:

數組x記錄了解空間樹中從根到當前擴展結點的路徑,這些信息已包含了回溯法在回溯時所需要的信息。利用數組x所含的信息,可將上述回溯法表示成非遞歸形式,進一步省去O(n)遞歸棧空間。

  n后問題的非遞歸迭代回溯法Backtrack可描述如下:

#include <iostream>
#include <cstdlib>
using namespace std;
class Queen{
    friend int nQueen(int);
private:
    bool Place(int k);
    void Backtrack(void);//.........
    int n,
        * x;
    long sum;
};
bool Queen::Place(int k)
{
    for(int j=1;j<k;j++)
        if( ( abs(k-j) == abs(x[j]-x[k]) ) ||( x[j] == x[k] ) )
            return false;
    return true;
}
void Queen::Backtrack(void)//......
{
    x[1] = 0;
    int k = 1;
    while(k>0)
    {
        x[k]+=1;
        while( (x[k]<=n) && !(Place(k)) )//k還不是最后的葉子結點,且位置沒有沖突
            x[k] += 1;
        if(x[k] <= n)
            if(k == n)//k是葉子結點
                sum++;
            else
            {
                k++;
                x[k] = 0;
            }
        else
            k--;
    }
}
int nQueen(int n)
{
    Queen X;
    X.n = n;
    X.sum = 0;
    int *p = new int [n+1];
    for(int i=0;i<=n;i++)
        p[i] = 0;
    X.x = p;
    X.Backtrack();//......
    delete [] p;
    cout<<X.sum<<endl;
    return X.sum;
}
int main()
{
    nQueen(4);
    nQueen(2);
    nQueen(3);
    return 0;
}

執行結果:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM