zoukankan      html  css  js  c++  java
  • HDU2553 N皇后问题——DFS

    N皇后问题

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 32229    Accepted Submission(s): 13874


    Problem Description
    在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上。
    你的任务是,对于给定的N,求出有多少种合法的放置方法。

     
    Input
    共有若干行,每行一个正整数N≤10,表示棋盘和皇后的数量;如果N=0,表示结束。
     
    Output
    共有若干行,每行一个正整数,表示对应输入行的皇后的不同放置数量。
     
    Sample Input
    1 8 5 0
     
    Sample Output
    1 92 10

    题意:中文题。。。。。

    思路:非常经典的搜索问题,用DFS来写。在棋盘中的棋,它的上下左右,以及左上,右上,左下,右下都不能有棋。因为是N*N的棋盘要放N个棋,可以知道一定是每一行放一个棋,所以我们可以按行进行搜索,逐一确定每一行的棋放在这一行的哪一个位置。

    这样有什么好处呢?这样就可以不用担心会发生两个棋子在同一行的情况了,而且也不用管这一行之前的行的情况了,因为能搜索到这一行,之前的每一个都应该是合法的。

    然后如何标记那些位置不能走呢?首先,行不用标记,原因上面说了,列也好办,开一个标记列的数组就行了。

    那左下和右下怎么办呢?仔细观察可以发现当前点到左下角45度这一条线路的所有点行数+列数的值都是相等的,而到右下角45度这一条线路行数-列数的值都是相等的,所以我们可以考虑用行和列的和来标记左下,行和列的差来标记右下,这样就是普通的DFS模板了。

    这题还有一个坑点,就是n是循环输入的,一组测试数据要DFS很多次,如果直接交的话会超时。因为n<=10,所以可以提前求出n==1到10的答案,存下,然后再输入n的时候直接用就行了。

    代码:

     1 #include<iostream> 
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<string>
     5 #include<cmath>
     6 #include<algorithm>
     7 #include<stack>
     8 #include<queue>
     9 #define eps 1e-7
    10 #define ll long long
    11 #define inf 0x3f3f3f3f
    12 #define pi 3.141592653589793238462643383279
    13 using namespace std;
    14 int ldown[20],rdown[30],vcolu[30]; //ldown标记左下,rdown标记右下,vcolu标记列 
    15 int n,ans[20];
    16 
    17 void DFS(int all,int cnt)
    18 {
    19     if(cnt == all+1) //如果最后一行也已经放了棋子,递归到了n+1行,答案++; 
    20     {
    21         ans[all]++;
    22         return;
    23     }
    24     
    25     for(int i=1; i<=all; ++i) //枚举这一行的每一列 
    26     {
    27         if(!vcolu[i] && !ldown[cnt+i] && !rdown[10+cnt-i]) //如果列,左下,右下都未标记不能走,则这一点可以走 
    28         {
    29             vcolu[i] = 1; //列标记为不能走 
    30             ldown[cnt+i] = 1; //左下标记为不能走 
    31             rdown[10+cnt-i] = 1; //右下。。。因为cnt-i可能为负,所以加上10避免 
    32             DFS(all,cnt+1); //递归搜索下一行 
    33             vcolu[i] = 0; //回溯 
    34             ldown[cnt+i] = 0;
    35             rdown[10+cnt-i] = 0;
    36         }
    37     }
    38     return;
    39 }
    40 
    41 int main()
    42 {
    43     memset(vcolu,0,sizeof(vcolu));
    44     memset(ldown,0,sizeof(ldown));
    45     memset(rdown,0,sizeof(rdown));
    46     memset(ans,0,sizeof(ans));
    47     for(int i=1; i<=10; ++i) //预处理枚举n为1到10的答案 
    48     {
    49         DFS(i,1);
    50     }
    51     while(cin>>n)
    52     {
    53         if(n==0) break;
    54         cout<<ans[n]<<endl;
    55     }
    56     return 0;
    57 }
  • 相关阅读:
    网线
    第19次实验
    矩阵乘法
    20次试验
    视频笔记
    1
    effective C++ 条款 34:区分接口继承和实现继承
    effective C++ 条款 35:考虑virtual函数以外的其他选择
    effective C++ 条款 29:为“异常安全”而努力是值得的
    effective C++ 条款 27:尽量少做转型动作
  • 原文地址:https://www.cnblogs.com/tuyang1129/p/9311913.html
Copyright © 2011-2022 走看看