回溯法-n皇后问题

问题描述:在nxn的棋盘上,放置彼此不受攻击的n个皇后。

规则:皇后可以攻击与之在同一行,同一列,同一斜线上的棋子。

以行为主导(不用再判断是否同行了)

算法设计:

(1)定义问题的解空间:问题解的形式为n元组:\{x_1,x_2,...,x_i,...,x_n\}

分量xi表示第i个皇后放置在第i行,第xi列。

(2)解空间的组织结构:m叉树

(3)搜索解空间:

约束条件:

x_i \neq x_j,不同列。

\left | i-j \right | \neq \left | x_i-x_j \right |,不同斜线。

限界条件:不存在放置方案好坏的问题。

搜索过程:从根开始,以深度优先搜索的方式进行搜索。根结点是活结点,并且是当前的扩展结点。

#include <iostream>
#include <cmath>

#define M 105
using namespace std;

int n;
int x[M];
int countn;

bool Place(int t) {
    bool ok = true;
    for (int j = 1; j < t; j++) {
        if (x[t] == x[j] || t - j == fabs(x[t] - x[j])) {
            ok = false;
            break;
        }
    }
    return ok;
}

void Backtrack(int t) {
    if (t > n) {
        countn++;
        for (int i = 1; i <= n; i++)
            cout << x[i] << " ";
        cout << endl;
        cout << "----------" << endl;
    } else
        for (int i = 1; i <= n; i++) {
            x[t] = i;
            if (Place(t))
                Backtrack(t + 1);
        }
}

int main() {
    cout << "请输入皇后的个数n: ";
    cin >> n;
    countn = 0;
    Backtrack(1);
    cout << "答案的个数是: " << countn << endl;
    return 0;
}

算法复杂度分析:

(1)时间复杂度:

除最后一层:1+n+n^2+...+n^{n-1}=\frac{n^n-1}{n-1}\approx n^{n-1}个结点需要扩展。

每个结点需要扩展n个分支:n^{n-1}n=n^n

每分支都要判断约束:n^n O(n)=O(n^{n+1})

叶子个数n^n,每个叶子输出最优解:n^n O(n)=O(n^{n+1})

因此,时间复杂度为:O(n^{n+1})

(2)空间复杂度:

x[]记录可行解,因此为:O(n)

算法优化扩展:

问题:解空间过大。

原因:使用了不同行作为显约束,使用了不同列,不同斜线作为隐约束

改进:使用不同行,不同列作为显约束,使用不同斜线作为隐约束,缩小解空间。此时解空间树变为排列树。

例如:

x1=1,则x2不能等于1

x1=1,x2=2,则x3不能等于1,2

猜你喜欢

转载自blog.csdn.net/qq_27437197/article/details/86746637