原题:洛谷P1562

  这个题的原理和8皇后的原理是一模一样的,就是必须要用n个皇后把每一个行填满,同时满足每一列,每一行,每一条对角线只有一个棋子。但如果按照原来的方法暴打的话只有60分(优化亲测无效)

  所以这个时候,我们可以用二进制来表示一波状态(可以类比状态压缩的二进制)。从上面的条件来看,我们需要表示的量有:行、列、两条对角线(向左的和向右的),我们用一个状态的某一位的1表示这个状态的这个位置不能放(已经有棋子)

  • 对于每一行:

  我们可以用DFS的深度来减少需要表示状态。(也就是说不用管,见代码)

  • 对于每一列:

  因为在DFS的时候,每一行都必然会放一个棋子,此时需要把这一位的列状态置为1,而且由此可知,当最后放满的时候,表示列的那个状态的必然全是1(终止条件

  •  对于向左上的对角线:

  从左上到右下,所以当前这一行影响的应该是下一行的右下一个(↘),然后这里需要注意的是这一行的最后一个的这种对角线是对下一行是没有影响的。举个例子(单就对角线来说):

  1. 这一行: 1表示有棋子)
  2. 下一行:

  这个时候可以看出来,这个状态相当于是>>=1。(因为最后一个没有影响所以它被消掉也没有影响)

  •  对于右上的对角线

  从右上到左下,影响下一行的左一个(↙)其他都和向左上的一样,只是这一行的第一个对下一行没有影响。举个例子:

  1. 这一行: 1表示有棋子)
  2. 下一行:

  这个时候可以看出来,这个状态相当于是<<=1。(第一个会被移到前面,超出查找范围,会被接下来的运算消掉)

  • 由此可见

  对于这一行来说,可以取的点应该是上一行的所有状态求并集(位或)之后二进制状态位为0的数。举个例子:

  1. 上一行传下来的状态: 列:
  2. 右对角线:
  3. 左对角线:
  4. 状态的并集:(这一行可以填充):
  5. 那么所以可以放棋子的位置应该是这一行的第2列和第5

这个时候,为了方便快速找到并集当中的可行解,联想树状数组的lowbit(),发现只要用1来表示可以放的位置即可,具体方法:并集取反后与全部位置(1~n位)都为1的一个值(all)作与运算(与all作与运算是为了把右对角线多向右移出去的除掉)举个例子:

  1. ~并集: (右对角线多出两位)
  2. all
  3. &all

这样只需要每一次取lowbit()之后把状态更新,并将并集减去lowbit()(将这一位置0表示已经取过)后继续DFS。

代码:(如果还没有理解可以用二进制检验函数单步走一下)

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. using namespace std;
  5. int n,map[]={},all=,cc=;//map[i]存放本来就不能放的点,cc表示可行借个数
  6.  
  7. //二进制检验函数
  8. int c[]={};
  9. void print_in_2(int x){
  10. for(int i=;i<;i++)c[i]=;
  11. while(x){
  12. c[]++;
  13. c[c[]]=x&;
  14. x>>=;
  15. }
  16. for(int i=n;i>;i--){
  17. printf("%d",c[i]);
  18. }
  19. cout<<endl;
  20. }
  21.  
  22. void Init(){
  23. scanf("%d",&n);
  24. char k[];//给出的地图
  25. for(int i=;i<n;i++){
  26. scanf("%s",k);
  27. for(int j=;j<n;j++){
  28. if(k[j]=='.')
  29. map[i]|=(<<j);//这里是将所给地图左右对称了,易证对称后与原图方案数相同
  30. }
  31. }
  32. all=(<<n)-;
  33.  
  34. /*for(int i=0;i<n;i++){
  35. print_in_2(map[i]);
  36. }*/
  37. }
  38. int low_bit(int x){//返回第一个1
  39. return x&-x;
  40. }
  41. void DFS(int deep,int line,int l_diag,int r_diag){//深度(行数)和上一行的状态:列、左对角线、右对角线
  42. if(line==all){//如果每一列都被填充了,找到答案
  43. cc++;
  44. return;
  45. }
  46. //注意:l_d.r_d,line是以1表示已经取过的位置,不是表示还可以放棋子,所以要与all取反
  47. int may=all&~(map[deep]|line|l_diag|r_diag);//取可行解,由于map中的1只能影响当前行,所以要在取一次或
  48. //print_in_2(may);
  49. int v;
  50. while(may){
  51. v=low_bit(may);
  52. may-=v;//将取出的那一位置0
  53. //print_in_2(may);
  54. DFS(deep+,line+v,(l_diag+v)>>,(r_diag+v)<<);//因为取出的那一位在任意状态中必为0,所以可以直接加上v来把那一位置1;
  55. }
  56. }
  57. void solve(){
  58. DFS(,,,);//我是从0开始存图所以以0为深度开始,其他位置在一开始都可取所以都为0
  59. printf("%d",cc);
  60. }
  61. int main(){
  62. Init();
  63. solve();
  64. return ;
  65. }

题解 洛谷P1562 【还是N皇后】的更多相关文章

  1. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  2. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  3. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  4. 题解-洛谷P4229 某位歌姬的故事

    题面 洛谷P4229 某位歌姬的故事 \(T\) 组测试数据.有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \( ...

  5. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  6. 题解-洛谷P4859 已经没有什么好害怕的了

    洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...

  7. 题解-洛谷P5217 贫穷

    洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...

  8. 洛谷P1219 :八皇后(DFS+回溯)

    题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 ...

  9. 题解 洛谷 P2010 【回文日期】

    By:Soroak 洛谷博客 知识点:模拟+暴力枚举 思路:题目中有提到闰年然后很多人就认为,闰年是需要判断的其实,含有2月29号的回文串,前四位是一个闰年那么我们就可以直接进行暴力枚举 一些小细节: ...

随机推荐

  1. gridview 合并单元格后,选中颜色重新绘制

    gv_docargo.RowStyle += OnRowStyle; private void OnRowStyle(object sender, DevExpress.XtraGrid.Views. ...

  2. IOC 概念

    转摘:https://www.cnblogs.com/DebugLZQ/archive/2013/06/05/3107957.html 博文目录 1.IOC的理论背景 2.什么是IOC 3.IOC也叫 ...

  3. HTTPie:替代 Curl 和 Wget 的现代 HTTP 命令行客户端

    HTTPie 工具是现代的 HTTP 命令行客户端,它能通过命令行界面与 Web 服务进行交互. -- Magesh Maruthamuthu 大多数时间我们会使用 curl 命令或是 wget 命令 ...

  4. HBase可用性分析与高可用实践

    HBase作为一个分布式存储的数据库,它是如何保证可用性的呢?对于分布式系统的CAP问题,它是如何权衡的呢? 最重要的是,我们在生产实践中,又应该如何保证HBase服务的高可用呢? 下面我们来仔细分析 ...

  5. windows 系统查看NVIDIA显卡GPU情况,nvidia-smi在windows上使用

    cd C:\Program Files\NVIDIA Corporation\NVSMI nvidia-smi   当batch_size设置越大的时候,GPU加速越明显,但是batch_size设置 ...

  6. tp5--相对路径和绝对路径

    首先,我们要先明白相对路径和绝对路径的理论: 绝对路径:是从盘符开始的路径,形如C:\windows\system32\cmd.exe相对路径:是从当前路径开始的路径,假如当前路径为C:\window ...

  7. php 超全局变量(整理)

    来源:https://www.cnblogs.com/wsybky/p/8745286.html 一.$GLOBALS 在GLOBALS数组中,每一个变量为一个元素,键名对于变量名,值对于变量的内. ...

  8. python学习13类2之封装

    '''''''''面向对象三大特性:封装,继承,多态1.封装: 类中以_或者__的属性,都是私有属性,禁止外部调用.'''class Student(object): def __init__(sel ...

  9. [Inno Setup] 安装完成后调用函数

    如果使用了通配符,每拷贝一个文件,函数都会被调用一次. Source: "path\test.exe"; DestDir: {app}; AfterInstall: LoadPer ...

  10. Spring框架中文件目录遍历漏洞 Directory traversal in Spring framework

    官方给出的描述是Spring框架中报告了一个与静态资源处理相关的目录遍历漏洞.某些URL在使用前未正确加密,使得攻击者能够获取文件系统上的任何文件,这些文件也可用于运行SpringWeb应用程序的进程 ...