Test 1: TEST OK [0.003 secs, 3372 KB] Test 2: TEST OK [0.003 secs, 3372 KB] Test 3: TEST OK [0.003 secs, 3372 KB] Test 4: TEST OK [0.003 secs, 3372 KB] Test 5: TEST OK [0.003 secs, 3372 KB] Test 6: TEST OK [0.008 secs, 3372 KB] Test 7: TEST OK [0.011 secs, 3372 KB] Test 8: TEST OK [0.078 secs, 3372 KB]
简]单介绍一下思想。
用位运算的方法来求的数量,DFS暴力搜索,搜出前3个答案。
还有一个就是棋盘是左右对称的,8*8的棋盘,第一个旗子放在第一排的前四个,和后四个结果应该完全一样。
对于棋盘n的奇偶分情况考虑一下就行了。 对半剪枝,实际上已经可以通过了。
对于非位运算的搜索还有一个优化,就是对于列是否被占用的判断,可以直接用链表,利用dancing link的思想,在穷举到最后的矩阵是很稀疏的,节约了穷举的时间。其实只加这一个优化不对半剪枝也是可以通过的~
当然最强的还是位运算,应为他对于穷举可以占用的格子的效率是最高的。
用3个数字分别表示,第deep行,每个格子的列,左斜排,右斜排是否被占用。
因为 对于deep行,他的左斜排被占用的是第一个,第二个格子。 那么deep+1行的时候,就是第0个,第一个格子。 说白了,就是这些会占用斜排的情况,在deep+1的时候,是会位移的。
位移?当然就是位运算的shl shr了~ 到这里基本方法就出来了。 听说这是穷举N皇后最快的方法。不知道用bitset的STL的话效率怎么样。
ultimate = (1 << n) - 1;
/* TASK:checker LANG:C++ */ #include <cstdio> int ultimate, n, ans(0); int tmp,outputbuff[13],ifstop=0;; bool a[3][35] = {0}; void dfs(int row, int ld, int rd) { if (row == ultimate) { ++ ans; return; } rd >>= 1, ld <<= 1; int tmp = row | ld | rd, p, ok = (~(row | ld | rd)) & ultimate; while (ok) { p = ok & -ok; dfs(row | p, ld | p, rd | p); ok ^= p; } } void get_ans(int deep) { if (ifstop == 3) return; if (deep == n) { ++ifstop; for (int i = 0; i != n - 1; ++ i) printf("%d ",outputbuff[i] + 1); printf("%d\n", outputbuff[n - 1] + 1); return; } for (int i = 0; i != n; ++ i) if (!a[0][i] && !a[1][deep - i + n + 1] && !a[2][i + deep]) { a[0][i] = a[1][deep - i + n + 1] = a[2][i + deep] = 1; outputbuff[deep] = i; get_ans(deep + 1); a[0][i] = a[1][deep - i + n + 1] = a[2][i + deep] = 0; } } int main() { freopen("checker.in", "r", stdin); freopen("checker.out", "w", stdout); scanf("%d",&n); get_ans(0); ultimate = (1 << n) - 1; #define p (1<<(i-1)) for (int i = 1; i <= (tmp = n >> 1); ++ i) dfs(p, p, p); ans <<= 1; if (n&1) dfs(1 << tmp, 1 << tmp, 1 << tmp); printf("%d\n", ans); return 0; }