[洛谷/题目] P1562 还是N皇后
声明
关于科学道理都会放进代码中,但是我们需要先了解一下位运算解这道题目的基础知识
我不是很会专业词语,所以仅介绍原理
位运算基础
众所周知,二进制是0和1
2^3 | 2^2 | 2^1 | 2^0 |
---|---|---|---|
8 | 4 | 2 | 1 |
0 | 1 | 0 | 1 |
对应的,加出来就是5,这就是二进制转换,我利用二进制里的0和1来记录是否走过或者其他的yes/no的数据,和bool数组一样
和bool数组相比,二进制虽然位数有限,但是非常方便,很多事情不需要人为的去干.
比如将bool数组的false的部分找出来,合并两个数组之类的.非常浪费精力
怎么单独更改一位呢?
这里有一个例子:
9: 1001 2: 0010 2 + 9 = 11 2 | 9 = 11 11: 1011
代码里有一个lowbit函数
这是怎么获取最后一个为1的那一位所表示的的数值呢?
这里有一个例子,具体是关于反码与补码的:
9: 1001 -9: 0111 9&(-9) = 1 1: 0001
"理论存在,实践开始"
#include <iostream> using namespace std; // n:棋盘格数 ans:答案个数 all:全部位数为1的二进制,是一个工具变量 int n, ans, all; // row:每一行默认的棋盘 (全局默认清空,但是赋值更保险(好习惯) int row[20] = {}; // 返回最后一个为1的那一位所表示的的数值 int lowbit(int x) { return x & (-x); } // d:当前第几行,从0开始 col:存储列是否用过 lv:存储左对角线是否用过 rv:存储右对角线是否用过 void dfs(int d, int col, int lv, int rv){ if(d == n) { // 能走到最后一步就记录次数 ans++; return ; } // 用位运算来获取遍历的依据 别忘了row是从1开始的 int vis = all & (~(row[d + 1] | col | lv | rv)); // 简单遍历 for(int i = vis; i; i -= lowbit(i)) { int x = lowbit(i); // 下一步 为了适应行数的+1,对角线就要对应的左移或者右移 dfs(d + 1, col + x, (lv + x) >> 1, (rv + x) << 1); } } int main(){ // 零时变量,获取字符用 char t; // 获取棋盘行列个数 cin >> n; // 初始化为所有位数为1 all = (1 << n) - 1; // 二位获取棋盘 for(int i = 1; i <= n; i++){ for(int j = 1; j <= n; j++){ cin >> t; // 点为不能走(禁区) if(t == '.') { // 单独一行一列对应一个字节,更改即可 // 加等于也是没有问题的 row[i] |= (1<<(n - j)); } } } // 开始深搜 0的所有位都为0 dfs(0, 0, 0, 0); // 换行好习惯 cout << ans << endl; return 0; }
总结
题目很好,可以锻炼思维,突破传统的思维方式,打开一个新世界的大门
好久没有写过markdown,生疏了
哦吼吼,能看到这个链接就说明我的文章被爬虫爬了
请尊重原作者: https://www.cnblogs.com/dffxd/小学四五年级可以学习到s组就是一个畸形的教育体系的体现,等国家发展起来了,吃枣药丸
本文来自博客园,作者:月神的使者,转载请注明原文链接:https://www.cnblogs.com/dffxd/p/luogu_p1562_bit_ans.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现