题目描述
相信大家都听过经典的“八皇后”问题吧?这个游戏要求在一个8×8的棋盘上放置8个皇后,使8个皇后互相不攻击(攻击的含义是有两个皇后在同一行或同一列或同一对角线上)。
桐桐对这个游戏很感兴趣,也很快解决了这个问题。可是,他想为自己增加一点难度,于是他想求出n皇后的解的情况。
你能帮助她吗?
输入输出格式
输入格式
一行,仅有一个数n(1≤n≤14),表示为n皇后问题。
输出格式
输出仅有一个数,表示n皇后时问题的解法总数。
输入输出样例
输入样例
8
输出样例
92
题解
经典dfs题。在搜索的时候枚举位置显然会超时,我们可以用三个数组分别记录当前列和当前两条对角线是否有被使用。具体细节如下。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> using namespace std; int n; int ans; int a[20],b[40],c[40]; void Queen(int x) { if(x>n) { ans++; return; } for(int y=1;y<=n;y++) if(!a[y]&&!b[x-y+n]&&!c[x+y-1]) { a[y]=b[x-y+n]=c[x+y-1]=1; Queen(x+1); a[y]=b[x-y+n]=c[x+y-1]=0; } } int main() { cin>>n; Queen(1); cout<<ans; return 0; }
但是极限数据还是可以把这个程序卡掉。我们可以思考,其实棋盘的摆放是满足对称性的,第一行我们只需要搜索一半就行了,这样就将时间复杂度缩小一半,刚好可以卡过。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<iostream> using namespace std; int n; int ans; int a[20],b[40],c[40]; void Queen(int x) { if(x>n) { ans++; return; } if(x==1) { for(int y=1;y<=n/2;y++) if(!a[y]&&!b[x-y+n]&&!c[x+y-1]) { a[y]=b[x-y+n]=c[x+y-1]=1; Queen(x+1); a[y]=b[x-y+n]=c[x+y-1]=0; } } else { for(int y=1;y<=n;y++) if(!a[y]&&!b[x-y+n]&&!c[x+y-1]) { a[y]=b[x-y+n]=c[x+y-1]=1; Queen(x+1); a[y]=b[x-y+n]=c[x+y-1]=0; } } } void Queen2(int x) { if(x>n) { ans++; return; } if(x==1) for(int y=n/2+1;y<=n/2+1;y++) if(!a[y]&&!b[x-y+n]&&!c[x+y-1]) { a[y]=b[x-y+n]=c[x+y-1]=1; Queen(x+1); a[y]=b[x-y+n]=c[x+y-1]=0; } else for(int y=1;y<=n;y++) if(!a[y]&&!b[x-y+n]&&!c[x+y-1]) { a[y]=b[x-y+n]=c[x+y-1]=1; Queen(x+1); a[y]=b[x-y+n]=c[x+y-1]=0; } } int main() { cin>>n; Queen(1); ans*=2; if(n%2==1) Queen2(1); cout<<ans; return 0; }
观察搜索过程,我们在枚举可放位置上花费了很多时间,其实我们可以直接用三个二进制数来表示当前行的可放位置,用lowbit来提取就行了。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <iostream> using namespace std; int n; int lim; int ans; void DFS(int a, int b, int c) { if(a == lim) { ++ans; return; } int tmp = lim & ~(a | b | c) , pos; while(tmp) { pos = tmp & -tmp; tmp -= pos; DFS(a + pos, b + pos >> 1, c + pos << 1); } return; } int main() { cin >> n; lim = (1 << n) - 1; int mid = 1 << (n >> 1); for(register int i = 1; i < mid; i <<= 1) { DFS(i, i >> 1, i << 1); } ans <<= 1; if(n & 1) DFS(1 << (n >> 1), 1 << (n >> 1) - 1, 1 << (n >> 1) + 1); // DFS(0, 0, 0); cout << ans; return 0; }