• POJ3239Solution to the n Queens Puzzle


    转载请注明出处:優YoU  http://user.qzone.qq.com/289065406/blog/1303915357

    大致题意:

    八皇后的扩展:N皇后问题

     PS: 我用了传统DFS回溯 和 构造法 两种方法去解决

    解题思路:

    先说说传统回溯的DFS思路:

    按行逐行填放皇后,标记已填放的列,两斜边的标记则利用 斜率 进行标记,当 准备填放的点 任一已填放的点 之间的斜率为1-1时,那么该位置不允许填放

     

    虽说是八皇后的扩展,但这么一扩展就难很多了。。。

    题目要求n值范围在 8300之内,Time还限制在1000ms ,传统的DFS回溯肯定是用不了,用传统的方法求解,n值超过30就爆了

     

    那么这题只能通过数学方法去解决,就是找出所有不同大小的棋盘中n个皇后的放置的一个规律,用数学的表达式或者序列去 构造 这个规律

    一般成功构造到公式后,题目就很水了,这题用构造法复杂度最坏只有O(n)n最大还是只有300。。。。

    但是难点就是如何推导出这个“规律”的公式了。。。

     

    我个人觉得必须至少用手工画几十个不同size的棋盘才可能看出一点眉目。。。挑战性太强了,有兴趣的同学可以手动试试。。。

    我做这题是盗用网上现成的公式(序列)的,说实话我很佩服找到这个规律的人,我觉得这个公式可以作为解决n皇后问题的专用公理了。。。

     

    构造法公式(序列):
    一、当n mod 6 != 2 n mod 6 != 3时:


    [2,4,6,8,...,n],[1,3,5,7,...,n-1]        (n
    为偶数)


    [2,4,6,8,...,n-1],[1,3,5,7,...,n ]       (n
    为奇数)

    二、当n mod 6 == 2 n mod 6 == 3


    (
    n为偶数,k=n/2;当n为奇数,k=(n-1)/2)


    [k,k+2,k+4,...,n],[2,4,...,k-2],[k+3,k+5,...,n-1],[1,3,5,...,k+1]         (k
    为偶数,n为偶数)

    [k,k+2,k+4,...,n-1],[2,4,...,k-2],[k+3,k+5,...,n-2],[1,3,5,...,k+1],[n]    
    (k
    为偶数,n为奇数)

    [k,k+2,k+4,...,n-1],[1,3,5,...,k-2],[k+3,...,n],[2,4,...,k+1]              (k
    为奇数,n为偶数)

    [k,k+2,k+4,...,n-2],[1,3,5,...,k-2],[k+3,...,n-1],[2,4,...,k+1],[n ]      (k
    为奇数,n为奇数)

     

    (上面有六条序列。一行一个序列,中括号是我额外加上的,方便大家辨认子序列,子序列与子序列之间是连续关系,无视中括号就可以了。第i个数为ai,表示在第iai列放一个皇后;... 省略的序列中,相邻两数以2递增。)

     1 /*代码一:构造法*/
    2
    3 //Memory Time
    4 //188K 16MS
    5
    6 #include<iostream>
    7 #include<cmath>
    8 using namespace std;
    9
    10 int main(int i)
    11 {
    12 int n; //皇后数
    13 while(cin>>n)
    14 {
    15 if(!n)
    16 break;
    17
    18 if(n%6!=2 && n%6!=3)
    19 {
    20 if(n%2==0) //n为偶数
    21 {
    22 for(i=2;i<=n;i+=2)
    23 cout<<i<<' ';
    24 for(i=1;i<=n-1;i+=2)
    25 cout<<i<<' ';
    26 cout<<endl;
    27 }
    28 else //n为奇数
    29 {
    30 for(i=2;i<=n-1;i+=2)
    31 cout<<i<<' ';
    32 for(i=1;i<=n;i+=2)
    33 cout<<i<<' ';
    34 cout<<endl;
    35 }
    36 }
    37 else if(n%6==2 || n%6==3)
    38 {
    39 if(n%2==0) //n为偶数
    40 {
    41 int k=n/2;
    42 if(k%2==0) //k为偶数
    43 {
    44 for(i=k;i<=n;i+=2)
    45 cout<<i<<' ';
    46 for(i=2;i<=k-2;i+=2)
    47 cout<<i<<' ';
    48 for(i=k+3;i<=n-1;i+=2)
    49 cout<<i<<' ';
    50 for(i=1;i<=k+1;i+=2)
    51 cout<<i<<' ';
    52 cout<<endl;
    53 }
    54 else //k为奇数
    55 {
    56 for(i=k;i<=n-1;i+=2)
    57 cout<<i<<' ';
    58 for(i=1;i<=k-2;i+=2)
    59 cout<<i<<' ';
    60 for(i=k+3;i<=n;i+=2)
    61 cout<<i<<' ';
    62 for(i=2;i<=k+1;i+=2)
    63 cout<<i<<' ';
    64 cout<<endl;
    65 }
    66 }
    67 else //n为奇数
    68 {
    69 int k=(n-1)/2;
    70 if(k%2==0) //k为偶数
    71 {
    72 for(i=k;i<=n-1;i+=2)
    73 cout<<i<<' ';
    74 for(i=2;i<=k-2;i+=2)
    75 cout<<i<<' ';
    76 for(i=k+3;i<=n-2;i+=2)
    77 cout<<i<<' ';
    78 for(i=1;i<=k+1;i+=2)
    79 cout<<i<<' ';
    80 cout<<n<<endl;
    81 }
    82 else //k为奇数
    83 {
    84 for(i=k;i<=n-2;i+=2)
    85 cout<<i<<' ';
    86 for(i=1;i<=k-2;i+=2)
    87 cout<<i<<' ';
    88 for(i=k+3;i<=n-1;i+=2)
    89 cout<<i<<' ';
    90 for(i=2;i<=k+1;i+=2)
    91 cout<<i<<' ';
    92 cout<<n<<endl;
    93 }
    94 }
    95 }
    96 }
    97 return 0;
    98 }

    ===========华丽的分割线==========

     

     1 /*传统DFS回溯 TLE (n超过30就难以搜索)*/
    2
    3
    4 #include<iostream>
    5 #include<cmath>
    6 using namespace std;
    7
    8 typedef class
    9 {
    10 public:
    11 int r,c;
    12 }location;
    13
    14 location pos[301]; //标记已填放的皇后坐标
    15
    16 bool col[301]; //列标记
    17 int n; //皇后数
    18
    19 bool DFS(int x,int p)
    20 {
    21 if(p==n)
    22 return true;
    23
    24 bool sign;
    25 for(int y=1;y<=n;y++) //枚举当前行x的每一列
    26 {
    27 bool flag=false;
    28 for(int i=1;i<=p;i++) //枚举每一个已填放的皇后
    29 if(abs(x-pos[i].r) == abs(y-pos[i].c)) //检查当前准备填放皇后的位置(x,y)是否在他们的斜边上
    30 { //其实就是标记斜率,斜率等于1或-1的格不允许填放皇后
    31 flag=true;
    32 break;
    33 }
    34
    35 if(!flag && !col[y])
    36 {
    37 col[y]=true;
    38 pos[p+1].r=x;
    39 pos[p+1].c=y;
    40 sign=DFS(x+1,p+1);
    41
    42 if(sign)
    43 return true;
    44 else
    45 col[y]=false; //回溯,pos[]的记录会自动被新值覆盖,所以不用特意处理
    46 }
    47 }
    48 return false; //当前行x的所有列y均不允许放皇后,说明前一行填错了
    49 }
    50
    51 int main(void)
    52 {
    53 while(cin>>n)
    54 {
    55 if(!n)
    56 break;
    57
    58 int p=0; //pos[]指针,已填充的棋子数
    59 memset(col,false,sizeof(col));
    60
    61 DFS(1,p);
    62
    63 for(int i=1;i<=n;i++)
    64 cout<<pos[i].c<<' ';
    65 cout<<endl;
    66 }
    67 return 0;
    68 }

     

     

  • 相关阅读:
    ASP.NET把客户机IP转换成真实地址(利用纯真 IP 数据库)
    关于分层走班教学的思考
    asp.net jQuery Ajax用户登录功能的实现
    C#判断网络地址 Url 是否存在的方法
    Asp.net获得远程网页源代码
    jQuery Ajax 调用aspx后台方法返回DataTable 的例子
    ASP.NET2.0中将GridView导出为Excel
    利用DataGrid显示某目录下的所有文件
    C#使用存储过程详细
    javascript获取当前日期时间
  • 原文地址:https://www.cnblogs.com/lyy289065406/p/2120582.html
Copyright © 2020-2023  润新知