题目链接~~>

这题用 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. sqlserver text类型字段错误 net.sourceforge.jtds.jdbc.ClobImpl@66fa192的解决方法

    1. SqlServer数据库中text/ntext字段,在用jtds1.2驱动时,会出现用getString()取不到值的问题,toString()也不行. 昨天查了下帮助可以通过简单的配置解决.即 ...

  2. C#Enum用Tuple保存值绑定到前端的CheckBox

    //把数字转成枚举 public static T[] NumStringsToEnums<T>(string enumNumString ) //where T:Enum { if (s ...

  3. Elasticsearch snapshot 备份的使用方法 【备忘】

    常见的数据库都会提供备份的机制,以解决在数据库无法使用的情况下,可以开启新的实例,然后通过备份来恢复数据减少损失.虽然 Elasticsearch 有良好的容灾性,但由于以下原因,其依然需要备份机制. ...

  4. .net core2.1 - ef core数据库迁移,初始化种子数据

    起因:早上偶然看见一篇文章说是ef core(2.x)使用种子数据,主表子表迁移时候,正常情况下说是无法迁移成功,索性就试试,结果是和ef6的一样,没感觉有什么大的区别.一切OK,见下面内容. 1.首 ...

  5. Nginx Java 日志切割脚本

    Nginx日志切割脚本: #!/bin/bash ########################################################################### ...

  6. WPF中矢量图制作和引用

    WPF程序有时需要适配不同大小的屏幕,图片是像素图的话,拉伸之后会变模糊,影响美观度,因此可以考虑使用矢量图.网上找到了相应的介绍:http://learnwpf.com/post/2006/06/0 ...

  7. 【转】通过 INotifyPropertyChanged 实现观察者模式

    通过 INotifyPropertyChanged 实现观察者模式 原博客地址 http://frankdzu.blog.sohu.com/117654536.html 普通观察者模式存在的问题 我们 ...

  8. jenkins(2): jenkins定时构建项目

    参考:http://blog.sina.com.cn/s/blog_b5fe6b270102v7xo.html https://blog.csdn.net/xueyingqi/article/deta ...

  9. php 连接redis服务器

    $redis = new Redis();                                           //实例化 $redis->connect("local ...

  10. jav实验二

    实验内容 1.初步掌握单元测试和TDD 2.理解并掌握面向对象三要素:封装.继承.多态 3.初步掌握UML建模 4.熟悉S.O.L.I.D原则 5.了解设计模式 实验内容 1.参考Intellj ID ...