N皇后问题的二进制优化详细思路
题目啊常规解法(DFS)在此就不赘述了。。。
直接进入正题。
众所周知,N皇后是NP完全类问题,n稍微大了点求解过程就会变得很长。
算法方面很难再有质的效率突破,但这不妨在其他细节上下下功夫。
揆诸常规解法,采用了数组来做mark,以行为每一层进行回溯算法,每个操作周期中无非就做了下面这些事情:
更新元素
判定元素
做出反应
更新元素这上面基本上想不到能有啥提升空间了(一次更新多个??似乎更加复杂了不谈不谈)。。。
做出反应嘛也同样没啥可以进步的地方(做出预判类反应??也复杂了,不谈不谈)。。。
很显然,有提升空间的就是判定元素环节了。
首先,从存储上考虑:
我们采用了三个数组来分别mark两个斜线和一列的占用情况(这里用"占用情况"表示此处是否能落子,如果被‘占用了’,则不能放棋子)
可不可以并成一个数组呢?那么这一个数组就要能够表示三个信息:当前位置一列两斜线的占用情况。有时即使能表示了,但是当移动到下一个位置的时候又得获得新的信息。。似乎不可行。
(于是我们又开始无聊地在纸上模拟算法过程了。。。。)
诶,然后就会发现,当进行DFS的时候,比如进行到第k层,放下了一个棋子,然后我们就要到下面一层去继续判定,此刻我们用到的信息是第k+1层的占用情况,而k+1的占用情况受到第k层情况的直接影响,如下图:

我们会发现第三层涂色的三个位置就不能放棋子了,
而除了第k层的影响,前k-1层也对第k+1层有着制约:

再回来看经典算法,每一次标记直接就否定了一条线上的位置,我们跳出这个思维,可不可以“步步为营”,进入到下一行的同时更新出下一行的占用信息?如果这样的话,一个数组足矣。
再思考,都已经一个数组了(相当于一串数字),而且每个格子就两个状态:有棋子,没棋子。
显然,二进制是不二选择!而且二进制运算的效率比较高!
大概的思路出来了,还有最后一个难点,就是前k-1层的占用信息如何安全过度到第k+1行。。
动手尝试了就不难发现这个规律:一个棋子会产生三种影响效果,斜向影响的,到下一层“占用”会斜向相应的方向偏移一格;垂直影响的,到下一层“占用”依旧在相应位置。
如图:

这时候就出现了三种类型的信息更新,一串二进制就难以实现了。。。那就三串呗,比起数组仍然不亏了。
大的逻辑疙瘩在脑子里基本上解开了,下面开始改代码:
首先,咱不用数组,改成int就够了。其次,考虑到每次信息更新的特点,我们可以用函数的形参来传递,省的搞个全局变量让人不爽。
函数头这亚子:
void Dfs(int i,int left,int col,int right)//分别是 层数 反斜杠mark 一列mark 斜杠mark
然后仍然是一般DFS解法的框架,只需要把其中用bool数组mark判断的地方用二进制方法进行替换即可。
放代码:
void Dfs(int i,int left,int col,int right)//分别是 层数 反斜杠mark 一列mark 斜杠mark
{
if (i > N) //判断是否已经枚举完了N行
{
showOneSolution(); //枚举完了就输出(此刻我们处于N+1行)
return; //返回到第N行
}
for (int j = N-; j >=; --j) //为啥J倒过来数呢?方便下面if中的偏移判断
{
if (!(((left|col|right)>>j)&))//(自己解读,有助于提升能力 (好吧我懒))
{
ans[i] = N-j;
Dfs(i + ,(left|(<<j))<<,(col|(<<j)),(right|(<<j))>>); //更新“占用信息”的工作就放在参数传递这里了
//这样子的好处就是,回溯的时候不用做什么恢复处理,
//因为这一层的东西基本没变动
}
}
}
这么多括号嵌套的。。哎呀我知道这可读性差,不提倡不提倡!
但是咱们现在是学习又不是工作,尽量读一些奇怪的代码有助于提高读代码能力(可着劲找借口··)
好了下面放上完整代码:
#include<iostream> using namespace std; int total = ;
int N = ;
int ans[] = { }; //结果还是要用数组存滴
void showOneSolution()//用来显示一个解
{
total++;
for (int i = ; i<=N; ++i)
{
cout << ans[i] << " ";
}
cout << endl;
}
void Dfs(int i,int left,int col,int right)//分别是 层数 反斜杠mark 一列mark 斜杠mark
{
if (i > N) //判断是否已经枚举完了N行
{
showOneSolution(); //枚举完了就输出(此刻我们处于N+1行)
return; //返回到第N行
}
for (int j = N-; j >=; --j) //为啥J倒过来数呢?方便下面if中的偏移判断
{
if (!(((left|col|right)>>j)&))//(自己解读,有助于提升能力 )
{
ans[i] = N-j;
Dfs(i + ,(left|(<<j))<<,(col|(<<j)),(right|(<<j))>>); //更新“占用信息”的工作就放在参数传递这里了
//这样子的好处就是,回溯的时候不用做什么恢复处理,
//因为这一层的东西基本没变动
}
}
} int main()
{
cin >> N;
Dfs(,,,);
cout << total;
system("pause");
return ;
}
总结:
巧妙运用位运算可以达到锦上添花的效果(装逼),不过大多数人看到位运算&|^<<>>啥的就打哈欠。
但是恰巧就有那么一些问题,能够完美契合二进制和位运算的特殊性质(不是指这个==),当你遇到的时候,你就会惊异于0101010···的奇妙。
N皇后问题的二进制优化详细思路的更多相关文章
- POJ-1276 Cash Machine 多重背包 二进制优化
题目链接:https://cn.vjudge.net/problem/POJ-1276 题意 懒得写了自己去看好了,困了赶紧写完这个回宿舍睡觉,明早还要考试. 思路 多重背包的二进制优化. 思路是将n ...
- hdu2844 Coins -----多重背包+二进制优化
题目意思:给出你n种硬币的面额和数量,询问它能够组合成1~m元中的几种情况. 这题如果直接按照完全背包来写的话,会因为每一种硬币的数目1 ≤ Ci ≤ 1000而超时,所以这里需要运用二进制优化来解决 ...
- hdu1059 多重背包(转换为01背包二进制优化)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1059 之前写过一个多重背包二进制优化的博客,不懂请参考:http://www.cnblog ...
- hdu 1171 Big Event in HDU(多重背包+二进制优化)
题目链接:hdu1171 思路:将多重背包转为成完全背包和01背包问题,转化为01背包是用二进制思想,即件数amount用分解成若干个件数的集合,这里面数字可以组合成任意小于等于amount的件数 比 ...
- HDU 2844 Coins 背包问题 + 二进制优化
题目大意:某个人有n种硬币,每种硬币价值为v,数量为c,问在总价值不超过m的条件下,最多有多少种组合方式. 题目思路: 1.对于某种硬币 如果v*c 大于 m,就意味着无论取多少枚硬币,只要总价值不大 ...
- Coins(多重背包+二进制优化)
Problem Description Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. On ...
- luogu||P1776||宝物筛选||多重背包||dp||二进制优化
题目描述 终于,破解了千年的难题.小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小FF可发财了,嘎嘎.但是这里的宝物实在是太多了,小FF的采集车似乎装不下那么多宝物.看来小FF只能含泪 ...
- HDU 5445 Food Problem(多重背包+二进制优化)
http://acm.hdu.edu.cn/showproblem.php?pid=5445 题意:现在你要为运动会提供食物,总共需要提供P能量的食物,现在有n种食物,每种食物能提供 t 能量,体积为 ...
- HDU 3591 (完全背包+二进制优化的多重背包)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3591 The trouble of Xiaoqian Time Limit: 2000/1000 M ...
随机推荐
- 「从零单排canal 06」 instance模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
- 远光武汉研发中心区块链事业部Java面试总结
面试在约定的时间准时进行,也是采用腾讯会议远程面试的方式.但是这是我第一次遇到面试官未打开摄像头的情况,后面经过沟通,双方都打开摄像头进行交流. 之前了解这个岗位主要是区块链相关的Java开发,所以事 ...
- 发送ajax请求时候注意的问题
1.在发送ajax请求一般都是默认为异步,就是不去等待后台响应直接可以继续发送, 但这样会有时候遇到一些问题,无法获得后台的响应参数, 所以在你打开编辑弹出框完成数据编辑后无法刷新页面, 这时候可能存 ...
- 记录一次线上实施snmp
公司要实施一个部级的项目,我们公司的提供的产品要对接下客户的一个平台监控平台,该监控平台使用snmp,我们公司的产品不支持snmp,所以由我负责在现网实施snmp,记录这次现网 一.生成编译规则 1. ...
- 【CF115E】Linear Kingdom Races 题解(线段树优化DP)
前言:前辈讲课时设的状态还是有些繁琐,感觉题解设的状态更简洁. -------------- 题目链接 题目大意:给定$n$条道路和$m$场比赛,每个道路修建需要$c_i$,每场比赛需要使用$[l_i ...
- Python多线程-ThreadLocal
参考:https://www.liaoxuefeng.com/wiki/1016959663602400/1017630786314240#0 ThreadLocal ThreadLocal变量虽然是 ...
- 04-Thread的生命周期
图示: 说明: 1.生命周期关注两个概念:状态.相应的方法 2.关注:状态a-->状态b:哪些方法执行了(回调方法) 某个方法主动调用:状态a-->状态b 3.阻塞:临时状态,不可以作为最 ...
- Python-关于正则表达式的总结
什么是正则表达式? 正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),用于字符串的 匹配 和 提取 等操作.正则表达式在所有编程语言中都是通用的. 很多人 ...
- Django 1.8.11 查询数据库返回JSON格式数据
Django 1.8.11 查询数据库返回JSON格式数据 和前端交互全部使用JSON,如何将数据库查询结果转换成JSON格式 环境 Win10 Python2.7 Django 1.8.11 返回多 ...
- 了解学习 Javascript, ES5 和 ES6之间的亲密关系
什么是Javascript JavaScript一种动态类型.弱类型.基于原型的客户端脚本语言,用来给HTML网页增加动态功能. JavaScript 的标准是 ECMAScript.截至 201 ...