深度优先搜索 之 CODE[VS] 1295 N皇后问题
/* 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 }