先看题才是最重要的:  

  

  这道题有点难理解,毕竟Code speaks louder than words,所以先亮代码后说话:

 #include<iostream>
using namespace std;
char s[];int n,map[],mod,ans;
void dfs(int deep,int line,int lr,int rl)
{
if(deep>n)
{
ans++;
return;
}
int pos=mod&(~(line|lr|rl|map[deep])),p;
while(pos)
{
p=pos&-pos;
pos-=p;
dfs(deep+,line+p,(lr+p)<<,(rl+p)>>);
}
}
int main()
{
cin>>n;
mod=(<<n)-;
for(int i=;i<=n;i++)
{
cin>>s;
for(int j=;j<n;j++)
map[i]=(s[j]=='.')+(map[i]<<);
}
dfs(,,,);
cout<<ans;
return ;
}

  这道题是一道搜索+二进制优化题,其实是八皇后的升级版,这就说明你的前置要求是要回普通的八皇后(不会点这里),初见此题,小编便鼓起勇气,without thinking twice就稍加改动提交了一遍原来八皇后的代码,结果甚是残忍。

  

  就算是开O2优化也没有用,亲测无效。那么就只能换个思路了,怎样能快一些呢?我们不禁会联想到二进制和位运算(推荐隔壁Alan_Anders的博客二进制和位运算符,小编懒得再多写一篇这样的博客了),我们可以尝试把这个问题简单化,只考虑最根本的问题:我们通常判断一个格子是否可以放置皇后,需要哪些要素呢?这就很显然了,只要懂国际象棋规则的,就一定知道只要这个位置没有被其他皇后攻击到就可以了呗,但是这样判断就很麻烦,比较耗时间,如果我们每一次能失去这个位置能否放置皇后的判断,时间复杂度将会降低不少吧?可这也意味着我们必须达到每一次搜索都能精准的判断出下一次放置的位置在哪里,这便有了五个要素的判断。

  1)这个位置本身题目要求就不能放,这就没办法了,只能用二维数组来存了如果是‘ . ’,那么就存为1,表示不能放,否则为0。1和0你们会想到什么,这就是二进制,那么我们是否可以改存成一维数组呢?举个栗子:

  

  这样我们是不是就可以以十进制存储二进制的方式存下每一行,定义一个数组map,按此图为例,那么map[1]=4,也就是(0010)₂,这里默认大家二进制会一些基础知识。

  【前方高能】

  2)在行上的冲突:这就很容易了,每放完一个皇后之后,只要把当前行号+1就可以了,比如现在在第二行放了一个皇后,那么下一次放就会在第三行(也就是2+1=3(行))。

  3)在列上的冲突:众所周知,皇后更攻击的范围包括了它所在的这一列,这样进行操作很简单,比如在第三列放了一个皇后,那么这一列永远也不能放置皇后了。

  那么说了,这么多,用什么来表示行列上的状态呢?行上就不必多说了,直接递归时行数的参数加1就可以了。那么列呢?也要用二进制,举个栗子:

  

  按照上面的图来说:这次我要在红色格子上放一次皇后,那么我下一次放置,哪些地方已经不能放了呢?显然,如下图所示的蓝色格子和第一行(因此表示行号的参数加1)已经不能放了。

  

  那么蓝色格子就会标记为1。下一行的列将会从(0000)₂更改成(0100)₂。

  4)左上到右下的对角线:我们依旧使用二进制来存储,如下图(还是同样的位置、同样的图):

  

  小编依旧要在红色格子上放置皇后,那么下一行哪些格子会因为左上到右下的对角线而不能放呢?如图所示,蓝色格子就一定不能。

  

  然后标记为1,于是表示左上到右下的对角线二进制值从(0000)₂变到了(0010)₂。

  4)右上到左下的对角线:同上,只不过会影响到下一行的左边而不是右边,从(0000)₂变到了(1000)₂ 。

  我想这些都应该很好理解吧,这是很简单易懂的,以这个栗子为栗,整理(0010)₂、(1000)₂、(0100)₂,用异或(符号:|)的方法合并成(1110)₂,这时我们能轻易的发现下一行的第四位一定是可以放皇后的,因为第四位是0,可是电脑不断找0是浪费时间的,但是找1是却是简单了,现将(1110)₂取反变成(0001)₂,那么又怎么找1?还记得树状数组中有个lowbit(假设有一个数x,那么x&-x便是lowbit(x)的值)吗?利用lowbit原理(恕小编不才,不会证明,但只要记住这个函数可以取到一个数的二进制数的最右边的1),就可以找到1的位置(也就是取反前0的位置),然后递归这个位置即可,因为可能下一行有>1个位置可以放皇后,所以要减去这个1,再找下一个1,然后继续进行递归。

  【前方高能】

  问题又来了!这个搜索该怎么写?我想你现在一定满肚子问题,现在小编就来回答一下这些问题,看一看与你现在想的一样不一样!

  Q:递归参数怎么写?有哪些要素组成?

  A:递归参数还是比较简单的,只需要4个参数,分别是行、列。左上到右下的对角线和右上到左下的对角线的状态。

  Q:这些状态怎么表示?

  A:全部使用二进制,1表示当前位置不可放,0表示当前位置可以放。

  Q:这些二进制表示的状态是怎么存储的,一直在说是二进制,到底怎么判断?

  A:一直在说二进制是为了好理解,但是我们要存成十进制的数,如(1011)₂要存成的数值为13。

  Q:为什么看到亮出的代码上会有mod=(1<<n)-1;和int pos=mod&(~(line|lr|rl|map[deep])),p;呢?mod到底是用来干啥的?

  A:注意:我们的二进制表示数一定只有n位,比如是4*4的棋盘,那么一定二进制表示出的数只有4位,举个栗子:当在第一行第一位放置一个皇后之后,那么下一行右上到左下的二进制表示的数为(10000)₂,那么将会多出去一位,为了保持计算的范围不变,那么如果我们用(10000)₂ &(1111)₂,那么结果将会取两个数都是1的位,由于这两个数没有二进制下相同的1的位,所以全部取0,所以下一行右上到左下的二进制表示的数会变成(0000)₂。其中mod就是(1111)₂,以n=4为例,自己计算一下便会知道mod=(1111)₂。

  Q:pos&-pos是什么鬼?

  A:注意看上面的解释,这句话可以当做lowbit(pos),实在不理解就只能去恶补树状数组了。

  Q:实在不理解dfs(deep+1,line+p,(lr+p)<<1,(rl+p)>>1);,肿么办?

  A:那我详细解释一下:deep是行号的意思,下一次放置皇后当然会在下一行喽;那么line呢?这个参数是用来表示列的状态的,比如说原来列的状态是(1001)₂(表示1,4列已有皇后放置),现在要在p(0100)₂(表示在下一行第二个位置放置皇后) 的位置摆放一个皇后,那么下一次列的状态将会是当前的状态(1001)₂+下一次要放皇后的位置(0100)₂=(1101)₂(从表示1,4列已有皇后放置变成了表示1,2,4列已有皇后放置)喽;斜着的对角线便是一大难点,为什么要左移(右移)?这是因为对角线是斜着的,举个栗子:比如说小编现在这一行表示左上到右下的对角线的二进制表示数为(0010)₂,那么这个红色方块内的棋子会通过左上到右下的对角线影响到第三行哪些格子呢?很显然是第三个位置上的棋子,此时第三行的状态将从(0000)₂改为(0001)₂,这有什么规律呢?当然是第三位的1变成了下一行第四位的1,向右移了1位,因此下一行要向右(向左)移。实在不理解文字描述,可以看下面的flash动画。

  

【搜索】还是N皇后的更多相关文章

  1. 搜索6--noi1700:八皇后问题

    搜索6--noi1700:八皇后问题 一.心得 二.题目 1756:八皇后 查看 提交 统计 提问 总时间限制:  1000ms 内存限制:  65536kB 描述 会下国际象棋的人都很清楚:皇后可以 ...

  2. 搜索5--noi1700:八皇后问题

    搜索5--noi1700:八皇后问题 一.心得 二.题目 1700:八皇后问题 查看 提交 统计 提问 总时间限制:  10000ms 内存限制:  65536kB 描述 在国际象棋棋盘上放置八个皇后 ...

  3. kb-01-a<简单搜索--dfs八皇后问题变种>

    题目描述: 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的 ...

  4. POJ - 1321 棋盘问题 dfs分层搜索(n皇后变式)

    棋盘问题 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 47960   Accepted: 23210 Descriptio ...

  5. 搜索:N皇后

    N皇后问题是DFS的代表性问题,其最难的地方就是在判重这里,想明白了怎么判重的话问题就很显然了. 这里给出两份代码,其中第一份代码的效率更好,就是在判重上下了功夫.当然,我记得还有使用位运算进行判重的 ...

  6. 搜索--P1219 N皇后

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

  7. 【搜索】N皇后问题

    原题传送门 思路 很经典的搜索题,但本蒟蒻卡了1个多小时,搜索部分很简单,但是判重的部分是真的蛋疼,我写了一个高效率的判重算法,但是无论检查多少遍都没有问题的算法却总是WA......后来我干脆写了一 ...

  8. 图-搜索-DFS-51. N皇后

    2020-03-15 19:49:59 问题描述: n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击. 上图为 8 皇后问题的一种解法. 给定一个整数 n ...

  9. 【luoguP1219】【USACO】八皇后

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

  10. UVa 11085 - Back to the 8-Queens

    题目:给你一个棋盘上的八个皇后.每行一个.如今让他们互相不攻击,每一个皇后仅仅能竖着移动, 一次能够移动到本列的不论什么位置,问最少移动几步.能满足要求. 分析:搜索,八皇后.由于八皇后仅仅有92组解 ...

随机推荐

  1. ELK 企业内部日志分析系统

    生产环境配置 亿级规模,建议64G内存+8核CPU ES JVM占用一半内存 生产环境的3节点的集群 https://blog.csdn.net/xuduorui/article/details/79 ...

  2. 区分IE8 、IE9 的专属css hack

    一般来说,我们写的结构比较好的时候,IE8/9下是没区别的.所以可能很少人关注只有IE8或只有IE9才识别的css hack. 因为IE8及以下版本是不支持CSS3的,但是我们如果使用css3,在IE ...

  3. 巧妙利用JQuery和Servlet来实现跨域请求

    在网上看到很多的JQuery跨域请求的文章,比较有意思.这里我发表一个Servlet与JQuery配置实现跨域的代码,供大家参考.不足之处请指教 原理:JavaScript的Ajax不可以跨域,但是可 ...

  4. 【CodeForces】708 C. Centroids 树的重心

    [题目]C. Centroids [题意]给定一棵树,求每个点能否通过 [ 移动一条边使之仍为树 ] 这一操作成为树的重心.n<=4*10^5. [算法]树的重心 [题解]若树存在双重心,则对于 ...

  5. 搭建cdh单机版版本的hive所遇到的问题总汇

    今天按照网上教程搭建了下 cdh 单机版的 hive  将相关配置记录下来 以便以后方便翻阅 版本 hive-0.13.1-cdh5.3.6.tar.gz 1. 直接解压 然后将 mysql驱动包 拷 ...

  6. 彻底解决mysql中文乱码

    mysql是我们项目中非常常用的数据型数据库.但是因为我们需要在数据库保存中文字符,所以经常遇到数据库乱码情况.下面就来介绍一下如何彻底解决数据库中文乱码情况. 1.中文乱码 1.1.中文乱码 cre ...

  7. 【BZOJ 1001】[BJOI2006]狼抓兔子(最大流)

    题目链接 最大流裸题,没什么好说吧,恰好点数多,考验网络流的效率,正好练\(Dinic\). #include <cstdio> #include <queue> #inclu ...

  8. UML相关说明

    在java开发中,有很多时候我们是在不断的处理类与类之间关系,其中这六种关系是:依赖.关联.聚合.组合.继承.实现. 它们的强弱关系是没有异议的:依赖 < 关联 < 聚合 < 组合& ...

  9. sqlite3_get_table()

    { sqlite3 *db; char *errmsg=NULL;    //用来存储错误信息字符串 char ret=0; int my_age=0;    //类型根据要提取的数据类型而定 cha ...

  10. Windows: 如何配置IPv6隧道

    清空隧道配置: netsh interface ipv6 set teredo disable netsh interface ipv6 6to4 set state disable netsh in ...