N皇后问题(状态压缩实现)
这题用 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皇后问题(状态压缩实现)的更多相关文章
- HDU2553N皇后问题(状态压缩)
这道题其实最简单的方法就是打表,直接DFS会超时,那就先运行一遍,找出1~10的值,打表即可,这里提供DFS和打表的数据 DFS:(白书上的)TLE #include <stdio.h> ...
- 转 状态压缩DP
引入 首先来说说“状态压缩动态规划”这个名称,顾名思义,状态压缩动态规划这个算法包括两个特点,第一是“状态压缩”,第二是“动态规划”. 状态压缩: 从状态压缩的特点来看,这个算法适用的题目符合以下的条 ...
- HDU-4529 郑厂长系列故事——N骑士问题 状态压缩DP
题意:给定一个合法的八皇后棋盘,现在给定1-10个骑士,问这些骑士不能够相互攻击的拜访方式有多少种. 分析:一开始想着搜索写,发现该题和八皇后不同,八皇后每一行只能够摆放一个棋子,因此搜索收敛的很快, ...
- dp乱写1:状态压缩dp(状压dp)炮兵阵地
https://www.luogu.org/problem/show?pid=2704 题意: 炮兵在地图上的摆放位子只能在平地('P') 炮兵可以攻击上下左右各两格的格子: 而高原('H')上炮兵能 ...
- HDU 2553 状态压缩
N皇后问题 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- POJ 3254. Corn Fields 状态压缩DP (入门级)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 9806 Accepted: 5185 Descr ...
- HDU 3605:Escape(最大流+状态压缩)
http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意:有n个人要去到m个星球上,这n个人每个人对m个星球有一个选择,即愿不愿意去,"Y" ...
- [HDU 4336] Card Collector (状态压缩概率dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336 题目大意:有n种卡片,需要吃零食收集,打开零食,出现第i种卡片的概率是p[i],也有可能不出现卡 ...
- HDU 4336 Card Collector (期望DP+状态压缩 或者 状态压缩+容斥)
题意:有N(1<=N<=20)张卡片,每包中含有这些卡片的概率,每包至多一张卡片,可能没有卡片.求需要买多少包才能拿到所以的N张卡片,求次数的期望. 析:期望DP,是很容易看出来的,然后由 ...
随机推荐
- 阿里云人脸识别测试接口出错 返回Body:{ "errno": 1031, "err_msg": "Invalid Image URL.", "request_id": "cdbe2927-e1bb-4eb1-a603-8fcd4b0b7fc8" }
错误信息如下 返回Body:{ "errno": 1031, "err_msg": "Invalid Image URL.", " ...
- GAN-生成对抗网络原理
最近一直在看GAN,我一直认为只有把博客看了一遍,然后再敲一遍.这样才会有深刻的感悟. GAN(生成式对抗网络)(GAN, Generative Adversarial Networks )是一种深度 ...
- node.js vue-axios和vue-resource
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Knockout示例:User数据CRUD
模拟数据user.json. { "page": 0, "rows": 0, "total": 161, "isSuccess&q ...
- [转] 合理使用npm version与npm dist-tag详解
第一步:发布第一个稳定版本 npm publish//1.0.0 第二步:修改文件继续发布第二个版本 git add -A && git commit -m "c" ...
- python之集合set
1.测试 # python2和python3方法列表相同 ops23 = ['add', 'clear', 'copy', 'difference', 'difference_update', 'di ...
- 【Android】Android取消EditText自动获取焦点
解决方法: 在EditText的父级控件中找一个,设置成 android:focusable="true" android:focusableInTouchMode="t ...
- (一)cygwin和vim——hello world!
好吧,我现在初出茅庐,一无所有,只有一台win xp.做什么呢?要不要试试Unix命令行编程的感觉,想到就做.Just try! 1.首先安装cygwin,最好是选择离线安装包. 2.默认选择安装所有 ...
- 再理解tcp backlog
在Linux 2.2以前,backlog大小包括了半连接状态和全连接状态两种队列大小.linux 2.2以后,分离为两个backlog来分别限制半连接SYN_RCVD状态的未完成连接队列大小跟全连接E ...
- nethogs命令执行报异常的解决方法