题目链接~~>

这题用 dfs()N范围一大了过不了,需要打表,用状态压缩可以状态压缩真是太强大了。

状态压缩 1:

在状态压缩中,通常用 ( 1 << N ) - 1 来表示最大状态MAXST,用 A | B 来合并A和B的状态位,用 A & ~B 来清除A状态中所有的B中的状态位。

一、DFS函数参数Col,MainDiag,ContDiag的表示意义:

当整形数Col,MainDiag,ContDiag的第X位为1时,表示因为之前摆放的皇后的纵向攻击,主对角线斜向攻击,副对角线斜向攻击而使得当前行摆放的皇后不能位于第X列。

二、Col == ( 1 << N ) - 1 的表示意义:

( 1 << N ) - 1 在二进制下就是N个1。这里Col中的1表示的是因为之前摆放的皇后的纵向攻击而使得当前行摆放的皇后不能位于的列,事实上也就是表示已经摆放了皇后的列。那么 Col == ( 1 << N ) - 1 也就表示N列每一列都摆放了皇后,也就是已经摆放了N个皇后,此时即获得一种皇后摆放方案。

三、emptycol = ( ( 1 << N ) - 1 ) & ~( Col | MainDiag | ContDiag ) 的表示意义:

首先 Col | MainDiag | ContDiag 的第X位为1时,显然是表示在综合了之前摆放的皇后的所有攻击方式之后当前行摆放的皇后不能位于第X列。

那么 emptycol = ( ( 1 << N ) - 1 ) & ~( Col | MainDiag | ContDiag ) 的第X位为1时,则是表示当前行摆放的皇后可以位于第X列。

四、curcol = ( emptycol ) & ( ( ~emptycol ) + 1 ) 的表示意义:

emptycol & ~emptycol 的结果显然是0,但是~emptycol一个巧妙的+1之后却让结果极富意义。

首先,2进制数字的+1进位(类比一下10进制)还是不难理解的:从最后一位开始,若当前位数字为1则将其进位为0并继续向前进位,若当前位数字为0则将其进位为1并停止进位。

现假设emptycol中的第一个1在第First位,而其后First-1位都是0。

那么~emptycol中的第一个0在第First位,而其后First-1位都是1。

当~emptycol进行+1进位时,其后First-1位全部进位为0,其第First进位为1,而其First之前的所有位则不变。

这时候再将emptycol与其进行&运算,显然答案的后First-1位为0,第First位为1,而First之前的所有位为0。

也就是说,curcol = ( emptycol ) & ( ( ~emptycol ) + 1 ) 中仅有一个1,而且这个1的位置即为emptycol中最后一个1的位置!

那么curcol的表示意义即为当前行摆放的皇后可以摆放的最后一列。

五、 emptycol &= ~curcol 的表示意义:

清除emptycol的最后一个1,表示当前已将皇后摆放在可以摆放的最后一列,之后不必再对此情况进行DFS。

因而while的循环结束条件是emptycol为0,也就是emptycol中没有1,表示已经没有需要DFS的情况了。

六、DFS递归的函数参数 Col | curcol,( MainDiag | curcol ) >> 1,( ContDiag | curcol ) << 1 的表示意义:

1、Col中的1表示因为之前摆放的皇后的纵向攻击而使得当前行摆放的皇后不能位于的列,而下一行的皇后显然也是不能摆放在这些列的curcol中唯一的1表示当前行皇后摆放的列,那么下一行的皇后因为当前行皇后的纵向攻击而不能摆放在这一列。所以 Col | curcol 即下一行的皇后因为其之前摆放的皇后的纵向攻击而不能摆放的列。

2、MainDiag中的1表示因为之前摆放的皇后的主对角线斜向攻击而使得当前行摆放的皇后不能位于的列。由于攻击是沿主对角线的,故而当前行影响的是第X列的话,那下一行影响的就是第X+1列。因此之前摆放的皇后的主对角线斜向攻击传递到下一行时则将变为 MainDiag >> 1。而因为当前行摆放状态为curcol的皇后的主对角线斜向攻击,下一行摆放的皇后将不能摆放在 curcol >> 1
中唯一的1的所在位置对应的列。所以 MainDiag >>1 | curcol >> 1 也就是 ( MainDiag | curcol ) >> 1 即下一行的皇后因为其之前摆放的皇后的主对角线斜向攻击而不能摆放的列。

3、( ContDiag | curcol ) << 1 的表示意义可类比第2点。

#include<stdio.h>
int N,SchemeNum;
void DFS(int Col,int MainDiag,int ContDiag)// Col 列放置皇后的情况,MainDiag 主对角线放置皇后的情况
{ // ContDiag 次对角线放置皇后的情况
if(Col==(1<<N)-1) // 找到一种放置方案
{
++SchemeNum;
return;
}
int emptycol=(((1<<N)-1)&~(Col|MainDiag|ContDiag)); //当前要放的行可以放的位置
while(emptycol)
{
int curcol=(emptycol)&((~emptycol)+1); //取第一位不为零的位
emptycol&=~curcol; //删除上一次放置的列
DFS(Col|curcol,(MainDiag|curcol)>>1,(ContDiag|curcol)<<1);// (ContDiag|curcol)<<1 最好&(1<<N)-1一下防止溢出
}
}
int main()
{
while(scanf("%d",&N)==1&&N)
{
SchemeNum=0;
DFS(0,0,0);
printf("%d\n",SchemeNum);
}
return 0;
}

状态压缩(2):

      用Col,First和Second分别表示标记了列,主对角线和副对角线的值,初始时全为0,这样的话(Col | First | Second)就表示到当前列时已经标记了的(不能放皇后的)点,那我们对其取反~操作,

也就是CanPut = ~(Col| First | Second),那得到的数就表示可以放的位置,所有1所在的位置也就是可以放的位置,那我们每次取出最低位的1(x & (-x))(这个我之前也不知道,网上查到的),那这样的话就得出了当前所有可以放的位置(不用像上面一个一个判断)(如果可以的话,尽可能自己推出递推关系,这里并不难)。

这里要注意的一个问题就是取反(~)操作之后,由于它高于N的位置也被置为了1,也就是相当于放到了某一行的棋盘的外面去了,所以我设置了一个值High = (1<<N)-1,然后每次得到一个可以放的位置的值CanPut,就对其和High取与(&)运算,这样的话就可以去掉高位的1,得到的数都是High以内的。

然后就是要处理已经处理了此行如何进行递归倒下一行的问题,假设在本行取出了一个CanPut的最低位LowBit,那么到下一行时,下一行的Col就是Col | LowBit, 当前行的First倒下一行时由于所有标记的点都往右移了一格,所以First>>1,再加上LowBit的右边一格也不能放,所以下一行主对角线已经标记了的就是(First>>1 | LowBit>>1),同理,副对角线标记了的就是(Second<<1 | LOwBit <<1).

代码:

#include <stdio.h>
int N,ans,High;
void DFS(int Col,int Fir,int Sec)
{
if(Col == High){ans++;return;}//所有的列都已经被标记了,说明每一列都放了
int CanPut = ((~(Col | Fir | Sec)) & High);
while(CanPut)
{
int LowBit = CanPut & (-CanPut);//取出最低位
DFS((Col|LowBit), ((Fir|LowBit)>>1), (((Sec|LowBit) <<1) & High));
CanPut &= (~LowBit);//去掉最低位
}
} int main()
{
while(~scanf("%d", &N) && N)
{
High = (1<<N)-1; ans = 0;
DFS(0,0,0);
printf("%d\n", ans);
}
return 0;
}

N皇后问题(状态压缩实现)的更多相关文章

  1. HDU2553N皇后问题(状态压缩)

    这道题其实最简单的方法就是打表,直接DFS会超时,那就先运行一遍,找出1~10的值,打表即可,这里提供DFS和打表的数据 DFS:(白书上的)TLE #include <stdio.h> ...

  2. 转 状态压缩DP

    引入 首先来说说“状态压缩动态规划”这个名称,顾名思义,状态压缩动态规划这个算法包括两个特点,第一是“状态压缩”,第二是“动态规划”. 状态压缩: 从状态压缩的特点来看,这个算法适用的题目符合以下的条 ...

  3. HDU-4529 郑厂长系列故事——N骑士问题 状态压缩DP

    题意:给定一个合法的八皇后棋盘,现在给定1-10个骑士,问这些骑士不能够相互攻击的拜访方式有多少种. 分析:一开始想着搜索写,发现该题和八皇后不同,八皇后每一行只能够摆放一个棋子,因此搜索收敛的很快, ...

  4. dp乱写1:状态压缩dp(状压dp)炮兵阵地

    https://www.luogu.org/problem/show?pid=2704 题意: 炮兵在地图上的摆放位子只能在平地('P') 炮兵可以攻击上下左右各两格的格子: 而高原('H')上炮兵能 ...

  5. HDU 2553 状态压缩

    N皇后问题 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  6. POJ 3254. Corn Fields 状态压缩DP (入门级)

    Corn Fields Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 9806   Accepted: 5185 Descr ...

  7. HDU 3605:Escape(最大流+状态压缩)

    http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,"Y" ...

  8. [HDU 4336] Card Collector (状态压缩概率dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336 题目大意:有n种卡片,需要吃零食收集,打开零食,出现第i种卡片的概率是p[i],也有可能不出现卡 ...

  9. HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)

    题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...

随机推荐

  1. VisualSVN Server如何安装和使用

    首先来下载和搭建SVN服务器. 现在Subversion已经迁移到apache网站上了,下载地址: http://subversion.apache.org/packages.html 这是二进制文件 ...

  2. NPOI操作Excel(二)--创建Excel并设置样式

    由于XSSF中的XSSFWorkbook和HSSF中的HSSFWorkbook拥有的属性.方法等都是一样的,故下面就已一个为例做为展示,他们都继承与一个接口:IWorkbook(命名空间:using  ...

  3. python函数之基础

    一: 函数的定义与调用 1.1 :函数的定义 def 关键字必需写 函数名必需是字母,数字,下划线组合,并且不能以数字开头 函数名后面要加括号然后“:” 为函数写注释是一个好习惯 # 函数的定义 de ...

  4. servlet获取多个同名参数

    String[] item = request.getParameterValues("参数名");

  5. 让simplejson支持datetime类型的序列化

    simplejson是Python的一个json包,但是觉得有点不爽,就是不能序列化datetime,稍作修改就可以了: 原文:http://blog.csdn.net/hong201/article ...

  6. SQL Server INSET/UPDATE/DELETE的执行计划

    DML操作符包括增删改查等操作方式. insert into Person.Address (AddressLine1, AddressLine2, City, StateProvinceID, Po ...

  7. Ueditor设置默认字体、字号、行间距,添加字体种类(转)

    Ueditor默认字体.字号.行间距的修改: ueditor默认字号是16号,默认字体为sans-serif,默认行间距为5px,如下图所示: 首先,修改ueditor.all.js文件中如上图红框中 ...

  8. 一脸懵逼学习Hive的安装(将sql语句翻译成MapReduce程序的一个工具)

    Hive只在一个节点上安装即可: 1.上传tar包:这个上传就不贴图了,贴一下上传后的,看一下虚拟机吧: 2.解压操作: [root@slaver3 hadoop]# tar -zxvf hive-0 ...

  9. C#学习-方法

    方法是由方法签名和一系列语句的代码块组成. 其中方法签名包括方法的访问级别(比如public或private).可修饰符(例如abstract关键字).方法名称和参数. C#也支持方法重载.方法重载指 ...

  10. uva 11367 (Dijkstra+DP)

    题意:一辆汽车在一张无向图中开告诉你每个城市加油的费用.每次给q个查询(起点,终点,油箱容量)问你最小花费是多少. 思路:一道Dijkstra状态的题目.在这种最短路问题中一维的dis数组记录的信息往 ...