状压DP入门详解+题目推荐
在动态规划的题型中,一般叫什么DP就是怎么DP,状压DP也不例外
所谓状态压缩,一般是通过用01串表示状态,充分利用二进制数的特性,简化计算难度。举个例子,在棋盘上摆放棋子的题目中,我们可以用1表示当前位置摆放棋子,用0表示当前位置不摆放棋子。
这样的话,就能够直接运用许多二进制运算的特性来实现对时间和空间的优化
例如:如果给你一个\(n*m\)的棋盘,让你放棋子,但是棋子两两不能相邻,求方案数
我们仅考虑暴力枚举每一行的情况,如果是普通用数组来存储,判断的时候对于相邻两行需要一个数一个数的看,不论是时间还是空间,都很难让人接受
但是如果用一个二进制数来存储每一行的情况,对于相邻两行,我们只需要进行一下与运算,如果有值,就说明不合法,这样不论是时间还是空间上,都进行了极大的优化
当然,这并不是说状压DP就是暴力枚举,这里只是举个例子来解释一下状压DP中的状态压缩这个过程
看完上面这些,还是不知道这是个什么东西,所以我们结合一道题目来演示一下,什么是状压DP
这是一道非常经典的状压例题,题意过于简单,我们不再赘述
我们首先考虑一下国王的特性:能够攻击到八个方向的棋子。也就是说,如果某个位置放置了棋子,它的九宫格内就不能再放置了。
我们可以将问题拆解,把九宫格看为三行,就可以分开考虑了
首先我们先考虑在当前行的棋子,只要一个棋子的左右没有相邻的棋子,那么就不冲突
再考虑上面那一行,只要一个棋子正上即左右侧上没有棋子则合法
最后再考虑一下下面那一行是否满足条件
那么我们只要枚举所有情况,再判断就可以了
显然,这样做复杂度实在太高了,9*9的棋盘计算到人类灭亡连枚举都枚举不完
看来我们需要把算法优化一下
我们考虑可不可以逐行枚举,先对每行的状态进行判断,在对上面一行和下面一行进行判断。我们会发现这样的做法是可行的,而且判断下一行是没有意义的,因为我们是逐行枚举,下一行还没枚举到有什么好枚举的。那么我们又会发现,这不是递推嘛。可是这样还是有点慢,怎么优化呢?
下面就是状压时刻了
我们可以在一开始将所有行内可行状态存储下来,由于可行状态远远小于总的状态数,这样可以大大优化我们的复杂度。如何判断这种状态是否没有冲突呢?用与运算就可以轻松判断。我们先预处理好第一行的情况,然后递推即可。
下面来看一下代码吧(内附详解)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cctype>
#define ll long long
#define gc getchar
#define maxn 10
#define maxm 105 //由于可行状态占比极小,所以行内的可行状态不到100
using namespace std;
inline ll read(){
ll a=0;int f=0;char p=gc();
while(!isdigit(p)){f|=p=='-';p=gc();}
while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();}
return f?-a:a;
}
int get(int x){ //求当前状态中1的数量
int sum=0;
while(x){
++sum;
x&=x-1; //初赛考了,你做对了吗
}
return sum;
}
int n,m,N,tot,s[maxm],w[maxm]; //s[i]表示第i种可行状态的具体摆放,w[i]表示第i种状态棋子的个数
ll ans,f[maxn][maxm][maxm]; //ans最终用来统计答案,f[i][j][l]表示第i行状态为第j种摆放l个棋子的方案数
int main(){
n=read();m=read();N=1<<n;
for(int i=0;i<N;++i){
if(i&i<<1)continue; //如果非零说明有相邻棋子,则不合法
s[++tot]=i;
w[tot]=get(i);
f[1][tot][w[tot]]=1; //第一行需要单独初始化
}
for(int i=2;i<=n;++i)
for(int j=1;j<=tot;++j)
for(int k=1;k<=tot;++k){
if(s[j]&s[k])continue; //三种与上一行有冲突的情况
if(s[j]&s[k]<<1)continue;
if(s[k]&s[j]<<1)continue;
for(int l=w[j];l<=m;++l) //这里非常重要!!l的取值影响到f数组的意义,l如果是从w[j]开始,那么f数组表示的是这一行及以前所有放l个棋子的方案数;如果l从w[j]+1开始,那么f数组表示的是到这一行正好有l个棋子的方案数,以前够了l个棋子的方案则没有被记录在这里面。这会影响到最后统计答案的,并且样例太水并不能看出来。这里一定要注意!!!
f[i][j][l]+=f[i-1][k][l-w[j]];
}
for(int i=1;i<=tot;++i) //统计答案就很简单了。不过如果是l是另一种写法还需要枚举1~n
ans+=f[n][i][m];
printf("%lld",ans);
return 0;
}
这就是状压DP,你是否理解了呢?不妨自己打一遍代码,能够加深理解哦。
例题
染色(一道我认为可用四进制状压解决的题目,如果有神仙成功了,希望能够告诉我一声,以证明我没口胡错)
茫茫人海相遇也算缘分,点个推荐好不好\(QwQ\)
状压DP入门详解+题目推荐的更多相关文章
- 树形DP入门详解+题目推荐
树形DP.这是个什么东西?为什么叫这个名字?跟其他DP有什么区别? 相信很多初学者在刚刚接触一种新思想的时候都会有这种问题. 没错,树形DP准确的说是一种DP的思想,将DP建立在树状结构的基础上. 既 ...
- 数位DP入门详解+题目推荐
\(update:2019-9-6\) 博客里某些东西没有解释清楚,完善了对应的解释 在开始之前,我们先来看一道题--题目链接 题目要求,相邻两位的差大于等于2,那么我们先来构造一个试一试. 比如说\ ...
- poj3254状压DP入门
G - 状压dp Crawling in process... Crawling failed Time Limit:2000MS Memory Limit:65536KB 64bit ...
- 状压dp入门
状压dp的含义 在我们解决动态规划题目的时候,dp数组最重要的一维就是保存状态信息,但是有些题目它的具有dp的特性,并且状态较多,如果直接保存的可能需要三维甚至多维数组,这样在题目允许的内存下势必是开 ...
- poj2686 状压dp入门
状压dp第一题:很多东西没看懂,慢慢来,状压dp主要运用了位运算,二进制处理 集合{0,1,2,3,....,n-1}的子集可以用下面的方法编码成整数 像这样,一些集合运算就可以用如下的方法来操作: ...
- POJ:1185-炮兵阵地(状压dp入门)
炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Description 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组 ...
- POJ 3254 & POJ 1185(状压DP入门)
Corn Fields Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 16773 Accepted: 8860 Desc ...
- poj 3254 状压dp入门题
1.poj 3254 Corn Fields 状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...
- 状压dp入门第一题 poj3254
题目链接 http://poj.org/problem?id=3254 转自http://blog.csdn.net/harrypoirot/article/details/23163485 #inc ...
随机推荐
- TPO-22 C1 Complain about a biased article
/* 加粗:语音部分 * 红色:单词部分 * 斜体:语法部分 * 下划线:信号词/句 */ 第 1 段 1.Listen to a conversation between a student and ...
- Xshell6远程访问linux及Xftp6远程针对linux系统中文件操作(附图文详解)
1.首先我们需要先做好前期准备工作,需要到XManager6官网上将Xshell及Xftp下载并安装,安装过程一直下一步就好了.这里是其官网:http://www.xshellcn.com/.安装完成 ...
- shell编程基础(转载)
Shell编程基础 原作者 Leal:请参阅页面底部的编者列表. 授权许可: 创作共享署名协议 GNU 自由文档许可证 注意:本文仍然在持续的修订之中,且错漏之处可能较多.如果能够阅读英语的话,可以考 ...
- Digitalocean + ss 搭建加密通信代理服务器
本文以 DigitalOcean + ss/ssr 配置加密通道***为例,记录了手动搭梯子的过程. 启动一个服务器实例的操作可以参考我的这篇博文,这里主要介绍 ss/ssr 的服务搭建过程. 首先 ...
- python如何与以太坊交互并将区块链信息写入SQLite
关于区块链介绍性的研讨会通常以易于理解的点对点网络和银行分类账这类故事开头,然后直接跳到编写智能合约,这显得非常突兀.因此,想象自己走进丛林,想象以太坊区块链是一个你即将研究的奇怪生物.今天我们将观察 ...
- nginx keepalived 高可用方案(转)
转自: https://www.cnblogs.com/leeSmall/p/9356535.html 一.Nginx Rewrite 规则 1. Nginx rewrite规则 Rewrite规则含 ...
- git 查看对比分支commit命令笔记
git log newheader(branch1) ^release(branch2) -- branch1 上比branch2多的commit 注意brnach2后面要--
- php之 常用的 流程管理
1.流程管理的用法是什么样的? 2.怎么发起想要的流程? 3.审批的人要是怎么审批通过? 4.流程审核是不是要挨个走过? 一.要有数据库的内容的 肯定会有表的,首先就是用户表了,然后就是流程表,用户编 ...
- “吃神么,买神么”的第二个Sprint计划
“吃神么,买神么”的第二个Sprint计划 一.现状 前台布局设计完成一个主页,可以让浏览者了解我们网站的功能,这是第一个阶段的Spring完成的事情.由于没有实际的功能体现,所以第二阶段开始 ...
- 【CSAPP笔记】5. 汇编语言——数据
本博客对于汇编的介绍基于32位机器的Intel x86系列处理器和IA32指令集,也涉及少部分x86-64.由于汇编知识相对复杂,这里只做简单介绍和记录,详细请参照书本! 数据格式 下面这张表格中体现 ...