当前位置:   article > 正文

回溯法-n皇后问题_回溯法解决n皇后问题时间复杂度

回溯法解决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 |,不同斜线。

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

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

  1. #include <iostream>
  2. #include <cmath>
  3. #define M 105
  4. using namespace std;
  5. int n;
  6. int x[M];
  7. int countn;
  8. bool Place(int t) {
  9. bool ok = true;
  10. for (int j = 1; j < t; j++) {
  11. if (x[t] == x[j] || t - j == fabs(x[t] - x[j])) {
  12. ok = false;
  13. break;
  14. }
  15. }
  16. return ok;
  17. }
  18. void Backtrack(int t) {
  19. if (t > n) {
  20. countn++;
  21. for (int i = 1; i <= n; i++)
  22. cout << x[i] << " ";
  23. cout << endl;
  24. cout << "----------" << endl;
  25. } else
  26. for (int i = 1; i <= n; i++) {
  27. x[t] = i;
  28. if (Place(t))
  29. Backtrack(t + 1);
  30. }
  31. }
  32. int main() {
  33. cout << "请输入皇后的个数n: ";
  34. cin >> n;
  35. countn = 0;
  36. Backtrack(1);
  37. cout << "答案的个数是: " << countn << endl;
  38. return 0;
  39. }

算法复杂度分析:

(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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/1013990
推荐阅读
相关标签
  

闽ICP备14008679号