zoukankan      html  css  js  c++  java
  • POJ 3239 -- Solution to the n Queens Puzzle

    Solution to the n Queens Puzzle
    Time Limit: 1000MS   Memory Limit: 131072K
    Total Submissions: 3872   Accepted: 1419   Special Judge

    Description

    The eight queens puzzle is the problem of putting eight chess queens on an 8 × 8 chessboard such that none of them is able to capture any other. The puzzle has been generalized to arbitrary n × n boards. Given n, you are to find a solution to the n queens puzzle.

    Input

    The input contains multiple test cases. Each test case consists of a single integer n between 8 and 300 (inclusive). A zero indicates the end of input.

    Output

    For each test case, output your solution on one line. The solution is a permutation of {1, 2, …, n}. The number in the ith place means the ith-column queen in placed in the row with that number.

    Sample Input

    8
    0

    Sample Output

    5 3 1 6 8 2 4 7

    Source

     
     
    解题思路:
     
      1)使用回溯法
      

      解空间树是一棵排列树。

      回溯法排列树的框架为:
          

      

      回溯法的复杂度如下所示:     

         

      高复杂度导致了一个必然的结果——超时。

     1 #include<iostream>
     2 #include<cstdlib>
     3 using namespace std;
     4 int x[310];
     5 int isSolved = 0;
     6 bool Constraint(int t)
     7 {///新加入的为x[t],所以只需判断x[t]与前t-1个棋子是否在同一条斜线上
     8     for(int j=1;j<t;j++)
     9     {
    10         if(abs(t-j) == abs(x[t] - x[j]))
    11             return 0;
    12     }
    13     return 1;
    14 }
    15 
    16 void BackTrack(int t,int n)
    17 {///t从1开始
    18     if(t == n+1 || isSolved == 1)
    19     {///只得到一个解
    20         ///生成解
    21         if(isSolved == 0)
    22         {
    23             for(int k = 1;k<=n;k++)
    24             {
    25                 cout<<x[k];
    26                 if(k != n) cout<<" ";
    27                 else cout<<endl;
    28             }
    29         }
    30         isSolved = 1;
    31         return;
    32     }else{
    33         for(int i=t;i<=n;i++)
    34         {
    35             swap(x[t],x[i]);
    36             if(Constraint(t) && isSolved == 0)
    37                 BackTrack(t+1,n);
    38             swap(x[t],x[i]);
    39         }
    40     }
    41 }
    42 
    43 int main()
    44 {
    45     int n;
    46     while(cin>>n && n!=0)
    47     {
    48         isSolved = 0;
    49         for(int i=0;i<=n;i++)
    50             x[i] = i;
    51         BackTrack(1,n);
    52     }
    53     return 0;
    54 }

     

      M皇后问题: 在M×M格的国际象棋上摆放M个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上。 
      根据场景,又有三种衍生问题: 
      ① 共有多少种摆法(即有多少种可行解) 
      ② 求出所有可行解 
      ③ 求任意一个可行解

      问题① 属于 禁位排列 问题,目前是存在通项公式直接求解的。 
      问题② 属于 搜索 问题,在网上也有多种解法,主流是 回溯法(另有衍生的位运算变种算法),但不管如何优化,回溯法都有一个致命的问题:M值不能过大(一般M=30已是极限)。 
      问题③ 属于 问题② 的子集,因此很多人的切入点依然是回溯法,也有启发式算法的解法:如遗传算法、还有刘汝佳在《算法艺术与信息学竞赛》提出的启发式修补算法。启发式算法在M<10000左右都是可解的,但是因为启发式算法均存在随机性,收敛速度视不同的收敛因子而变化(我看过某篇论文称启发式算法在M=10000时的耗时等价于回溯法M=30的耗时)。

      但早在1969年, 问题③ 的解就被E. J. Hoffman、J. C. Loessi 和R. C. Moore找到了潜在的数学规律,通过推导出数学公式,利用 构造法 使得该问题可在O(1) 的时间复杂度得到解

          2)构造法

      目前网上流传的通解公式,则是为了便于编程,在坐标变换后得到的:
      变换坐标后的求解公式如下:
      ① 当m mod 6 != 2 且 m mod 6 != 3时:
      (A1):[2,4,6,8,...,m], [1,3,5,7,...,m-1] (m为偶)
      (A2):[2,4,6,8,...,m-1], [1,3,5,7,...,m-2], [m] (m为奇)

      ② 当m mod 6 == 2 或 m mod 6 == 3时,
      令 n= m / 2 (m为偶数) 或 n = (m-1)/2 (m为奇数)
      (B1):[n,n+2,n+4,...,m], [2,4,...,n-2], [n+3,n+5,...,m-1], [1,3,5,...,n+1] (m为偶,n为偶)
      (B2):[n,n+2,n+4,...,m-1], [1,3,5,...,n-2], [n+3,...,m], [2,4,...,n+1] (m为偶,n为奇)
      (B3):[n,n+2,n+4,...,m-1], [2,4,...,n-2], [n+3,n+5,...,m-2], [1,3,5,...,n+1], [m] (m为奇,n为偶)
      (B4):[n,n+2,n+4,...,m-2], [1,3,5,...,n-2], [n+3,...,m-1], [2,4,...,n+1], [m] (m为奇,n为奇)

      上面有六条解序列:
      一行一个序列(中括号是我额外加上的,以便辨认子序列)
      第i个数为j,表示在第i行j列放一个皇后.
      子序列与子序列之间的数序是连续关系(无视中括号就可以了), 所有子序列内j的递增值为2

      证明:N皇后问题 - 构造法原理与证明: 时间复杂度O(1)
     
     1 #include<iostream>
     2 using namespace std;
     3 void Print(int x,int y)
     4 {
     5     for(int t = x;t<=y;t+=2)
     6     {
     7         cout<<t;
     8         if(t != y) cout<<" ";
     9     }
    10 }
    11 int main()
    12 {
    13     int m;
    14     while(cin>>m && m != 0)
    15     {
    16         if(m%6 != 2 && m %6 !=3)
    17         {
    18             if(m%2 == 0)//m为偶数
    19             {
    20                 Print(2,m);cout<<" ";Print(1,m-1);cout<<endl;
    21             }else{
    22                 Print(2,m-1);cout<<" ";Print(1,m);cout<<endl;
    23             }
    24         }else{
    25             int n = m/2;
    26             if(m%2==0 && n%2==0)
    27             {
    28                 Print(n,m);cout<<" ";Print(2,n-2);cout<<" ";Print(n+3,m-1);cout<<" ";Print(1,n+1);cout<<endl;
    29             }else if(m%2 == 0 && n%2 == 1)
    30             {
    31                 Print(n,m-1);cout<<" ";Print(1,n-2);cout<<" ";Print(n+3,m);cout<<" ";Print(2,n+1);cout<<endl;
    32             }else if(m%2 == 1 && n%2 == 0)
    33             {
    34                 Print(n,m-1);cout<<" ";Print(2,n-2);cout<<" ";Print(n+3,m-2);cout<<" ";Print(1,n+1);cout<<m;cout<<endl;
    35             }else{
    36                 Print(n,m-2);cout<<" ";Print(1,n-2);cout<<" ";Print(n+3,m-1);cout<<" ";Print(2,n+1);cout<<m;cout<<endl;
    37             }
    38         }
    39 
    40     }
    41     return 0;
    42 }

  • 相关阅读:
    linq 查询-“必须是可缩小的节点”
    在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。”
    将字符串转换为double类型的list
    mysql新增用户无法授权!? 解决方案
    eclipse项目有红色感叹号
    错误: 找不到或无法加载主类 java操作hbase出错
    org.apache.hadoop.conf.Configuration无法引用 解决方法
    jdbc的数据库驱动类DriverManager.getConnection()详解
    MySQL [Err] 1055--1064
    控制反转
  • 原文地址:https://www.cnblogs.com/yxh-amysear/p/8418939.html
Copyright © 2011-2022 走看看