1 条题解
-
0
自动搬运
来自洛谷,原作者为

karma
**搬运于
2025-08-24 21:26:30,当前版本为作者最后更新于2017-11-06 09:45:38,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
此题是一个练习位运算的好题
由于楼下题解解释过少,我来进行补充.
其实此题的正解就是位运算,用其他方法会TLE(打表除外)
分析:
-
逐行放置皇后,首先排除每行有多个皇后互相排斥的情况
-
用二进制表示状态.1表示该点不能放(与其他位置的皇后排斥或初始状态就不能放).0表示该点可以放皇后
-
用sta[]来存储初始状态,将'.'位 置为1
-
dfs保存四个参数:当前行的状态,从左上到右下对角线的状态,从右上到左下对角线的状态,当前为第几行
-
获取当前哪一位可以放置皇后:将四者取并集(即将四者进行或运算).得到的状态中为0的就可以放置皇后.
-
为了快速得到可以放置皇后的位置,对上一步得到的状态进行取反.转换成快速得到1的位置.
-
用树状数组中的lowbit()就可以得到从右向左的第一个1
-
将状态中的1减掉,继续找下一个1
-
更新"将是下一行的状态",由于对角线是斜着影响的,所以左上到右下对角线的状态需要左移一位,右上到左下对角线的状态需要右移一位.
-
知道当前行的状态全为1时,即每一行都有一个皇后时,ans++;
#include<cstdio> #define xianzhi ~(now|ld|rd|sta[d]) #define lowbit(pos) pos&-pos #define youzuo (ld+p)<<1 #define zuoyou (rd+p)>>1 int n,all,sta[25],ans; void dfs(int now,int ld,int rd,int d){//now这个状态限制的是"列之间的冲突" if(now==all){ans++;return ;} int pos=all&xianzhi,p; while(pos){ p=lowbit(pos); pos-=p; dfs(now+p,youzuo,zuoyou,d+1); } } int main(){ scanf("%d",&n); all=(1<<n)-1;//最终状态(即全部放完的状态) char c[20]; for(int i=1;i<=n;++i){ scanf("%s",c+1); getchar();//消除行末回车 for(int j=1;j<=n;++j){ if(c[j]=='.')sta[i]|=(1<<(n-j));//将sta[i]的"第j位"置为1 } } dfs(0,0,0,1); printf("%d",ans); return 0; } -
- 1
信息
- ID
- 555
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者