/*
dfs,关键:检查皇后会发生攻击的状态。
两种方法:(第二种,速度更快)
(1)void Solve(int row, int colUsed);
常规办法,判断状态是否非法的方法:列上通过位运算;左斜、右斜通过遍历。
(2)void SolveBitOperation(unsigned col, unsigned tiltLeft, unsigned tiltRight);
完全位运算,具体参考代码注释。
另外可参考Matrix67的博客(有图,很形象):http://www.matrix67.com/blog/archives/266
C++实现参考:http://www.cnblogs.com/lee41sum/archive/2010/04/22/1717986.html
*/
1 #include <iostream>
2 #include <cstdlib>
3 #include <cstdio>
4 #include <cstddef>
5 #include <iterator>
6 #include <algorithm>
7 #include <string>
8 #include <locale>
9 #include <cmath>
10 #include <vector>
11 #include <cstring>
12 #include <map>
13 #include <utility>
14 #include <queue>
15 #include <stack>
16 #include <set>
17 using namespace std;
18 const int INF = -0x3f3f3f3f;
19 const int MaxN = 55;
20 const int modPrime = 3046721;
21
22 int n;
23 bool isUsedNode[20][20];
24 int answer = 0;
25
26 //----------------------------------方法一----------------------------------
27 bool isAttack(int row, int col, int colUsed)
28 {
29 if (colUsed&(1 << col))
30 {
31 return true;
32 }
33 for (int i = row - 1, j = col - 1, k = col + 1; i > 0; --i, --j, ++k)
34 {
35 if (j > 0)
36 {
37 if (isUsedNode[i][j])
38 {
39 return true;
40 }
41 }
42 if (k <= n)
43 {
44 if (isUsedNode[i][k])
45 {
46 return true;
47 }
48 }
49 }
50 return false;
51 }
52
53 void Solve(int row, int colUsed)
54 {
55 if (row == n+1)
56 {
57 ++answer;
58 return;
59 }
60 for (int col = 1; col <= n; ++col)
61 {
62 if (!isAttack(row, col, colUsed))
63 {
64 isUsedNode[row][col] = true;
65 Solve(row + 1, colUsed | (1 << col));
66 isUsedNode[row][col] = false;
67 }
68 }
69 }
70
71 //----------------------------------方法而----------------------------------
72 unsigned limN; // N个皇后目标状态(所有列都已有皇后,注:这里的列是指将N行压缩成一行,一共有N列)
73 void SolveBitOperation(unsigned col, unsigned tiltLeft, unsigned tiltRight)
74 { // 列非法位置 左斜产生的非法位置 右斜产生的非法位置
75 if (col == limN)
76 {
77 // 所有列都已有皇后
78 ++answer;
79 return;
80 }
81 unsigned freePosSet = limN&(~(col | tiltLeft | tiltRight)); // 获得不会发生冲突的列集合
82 while (freePosSet)
83 {
84 unsigned freePos = freePosSet&((~freePosSet) + 1);
85 // 在不会发生冲突的列集合中,获取最右边的列位置(如果直接想不出来这条语句的原因,举个例子自己推演一下)
86 /*
87 eg:
88 freePosSet 二进制:01010010
89 ~freePosSet 二进制:10101101
90 (~freePosSet)+1 二进制:10101110
91 freePosSet&((~freePosSet) + 1) 二进制:00000010
92
93 */
94 freePosSet -= freePos;
95 // 在没有冲突的列集合中,去掉当前行已用过的列位置
96 SolveBitOperation(col | freePos, (tiltLeft | freePos) << 1, (tiltRight | freePos) >> 1);
97 //到了下一行: 增加一个非法列位置(即当前行皇后所占的列位置)
98 // 因为当前行多了一个皇后,所以左斜到下一行多了一个非法位置,右斜到下一行多了一个非法位置
99 }
100 }
101
102 int main()
103 {
104 #ifdef HOME
105 freopen("in", "r", stdin);
106 //freopen("out", "w", stdout);
107 #endif
108
109 memset(isUsedNode, false, sizeof(isUsedNode));
110 cin >> n;
111 // 方法一
112 //Solve(1, 0);
113 // 方法二
114 limN = (1 << n) - 1;
115 SolveBitOperation(0, 0, 0);
116 cout << answer << endl;
117
118 #ifdef HOME
119 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
120 _CrtDumpMemoryLeaks();
121 #endif
122 return 0;
123 }