深度优先搜索 之 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 }

 


posted @ 2015-12-04 18:45  JmingS  阅读(246)  评论(0编辑  收藏  举报