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 }
原文地址:https://www.cnblogs.com/tuyang1129/p/9311913.html