状压DP详解+题目
介绍
状压dp其实就是将状态压缩成2进制来保存 其特征就是看起来有点像搜索,每个格子的状态只有1或0 ,是另一类非常典型的动态规划
举个例子:有一个大小为n*n的农田,我们可以在任意处种田,现在来描述一下某一行的某种状态:
设n = 9;
有二进制数 100011011(九位),每一位表示该农田是否被占用,1表示用了,0表示没用,这样一种状态就被我们表示出来了:见下表

位运算
为了更好的理解状压dp,首先介绍位运算相关的知识。
& 符号,x&y,会将两个十进制数在二进制下进行与运算(都1为1,其余为0) 然后返回其十进制下的值。例如3(11)&2(10)=2(10)。
|符号,x|y,会将两个十进制数在二进制下进行或运算(都0为0,其余为1) 然后返回其十进制下的值。例如3(11)|2(10)=3(11)。
^ 符号,x^y,会将两个十进制数在二进制下进行异或运算(不同为1,其余 为0)然后返回其十进制下的值。例如3(11)^2(10)=1(01)。
~ 符号,~x,按位取反。例如~101=010。
<< 符号,左移操作,x<<2,将x在二进制下的每一位向左移动两位,最右边用0填充,x<<2相当于让x乘以4。 ’>>’符号,是右移操作,x>>1相当于给x/2,去掉x二进制下的最右一位
1.判断一个数字x二进制下第i位是不是等于1。(最低第1位)
方法:if(((1<<(i−1))&x)>0) 将1左移i-1位,相当于制造了一个只有第i位 上是1,其他位上都是0的二进制数。然后与x做与运算,如果结果>0, 说明x第i位上是1,反之则是0。
2.将一个数字x二进制下第i位更改成1。 方法:x=x|(1<<(i−1)) 证明方法与1类似。
3.将一个数字x二进制下第i位更改成0。 方法:x=x&~(1<<(i−1))
4.把一个数字二进制下最靠右的第一个1去掉。 方法:x=x&(x−1)
题目
P1896 [SCOI2005]互不侵犯
一道很好的状压dp题。
由于每个格子只有两种状态:放国王 和 不放国王 ,用 1 表示放国王,0 表示不放国王;那么把每个格子的数连起来就是 \((101001)_2\) ,这个数在十进制下是: \((101001)_2\) = \((41)_{10}\)

所以状压 dp 的套路就是不断的去枚举表示状态的数,去转移即可。
状态设置:
按照状压 dp 的套路,我们设状态:dp[i][S][j] 表示我们已经选到了第 i 行,第 i 行的状态为 S,用了 j 个国王的方案数;
首先看一下国王的攻击范围(以其为中心的九宫格):红色代表国王位置,蓝色代表它的攻击范围:

思考:如果我们第 i−1 行的第 j 列放好国王之后,那么对第 i 行的影响是什么呢?也就是国王在第 i 行上的攻击范围内的格子不能再放国王了:

也就是说,如果第i−1 行的状态S1(表示状态的二进制数)的第 j 位是 1(放国王)的话,第 i 行的状态 S2 的第 j−1,j,j+1 位一定为 0(不能再放国王了),否则就是不合法的状态;
所以我们就得出了表示这三个位置的方法,那么 S2 必须满足什么条件才可能由 S1 转移过去呢?
这是需要位运算了>_<!
条件:\((S2 & S1 ==0) && ( (S2<<1) & S1==0) && ( (S2>>1) & S1==0)\)
我们发现这样写有点长,还可以这样写:\((S2∣(S2>>1)∣(S2<<1)) &S1==0\)
当然,我们处理完行间的限制后,接下来就要处理行内的限制了;
一个国王的左右格子内不能再放国王了,这就是行内的限制!
直接上 \(((S2<<1) & S2==0) && ((S2>>1) & S2==0)\)(更简洁:\(((S2<<1) & S2==0) && ((S2>>1) & S2==0)\))
最后就是普通的dp了
#include <bits/stdc++.h>
using namespace std;
int n,k;
long long cnt[1005],ok[1005];
int h=0;
long long f[15][1005][105];
int main(){
scanf("%d%d",&n,&k);
for (int s=0;s<(1<<n);s++){
if (((s<<1)|(s>>1))&s)continue;
int tot=0;
for (int j=0;j<n;j++)
if (s&(1<<j)) tot++;
cnt[++h]=tot;
ok[h]=s;
}
f[0][1][0]=1;
for (int i=1;i<=n;i++)
for (int j=1;j<=h;j++)
for (int l=cnt[j];l<=k;l++)
for (int t=1;t<=h;t++){
if (!(ok[t]&ok[j])&&!(ok[t]&(ok[j]<<1))&&!(ok[t]&(ok[j]>>1))){
f[i][j][l]+=f[i-1][t][l-cnt[j]];
}
}
long long ans=0;
for (int i=1;i<=h;i++) ans+=f[n][i][k];
printf("%lld",ans);
return 0;
}
P1879 [USACO06NOV]Corn Fields G
和上题差不多
也是有两个条件
1.田是否可以种
2.种的地方上下左右不能种
判断好之后,上代码
#include <bits/stdc++.h>
#define MOD 1000000000
using namespace std;
int m,n;
int F[15];
int a[15][15];
int f[15][5005];
bool cnt[5005];
int h=0;
int ans;
int main(){
scanf("%d%d",&m,&n);
for (int i=1;i<=m;i++){
for (int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
F[i]=(F[i]<<1)+a[i][j];
}
}
for (int s=0;s<(1<<n);s++)
cnt[s]=((s&(s<<1))==0)&&((s&(s>>1))==0);
f[0][0]=1;
for (int i=1;i<=m;i++){
for (int l=0;l<(1<<n);l++){
if (cnt[l]&&((l&F[i])==l)){
for (int s=0;s<(1<<n);s++){
if (!(l&s))
f[i][l]=(f[i][l]+f[i-1][s])%MOD;
}
}
}
}
for (int i=0;i<(1<<n);i++){
ans+=f[m][i];
ans%=MOD;
}
printf("%d\n",ans);
return 0;
}
P2704 [NOI2001] 炮兵阵地
可以说是上一题的plus。
只要多加一次的循环就可以了
由于觉得太烦就先把1行2行先处理一下
#include <bits/stdc++.h>
using namespace std;
int n,m;
int f[105][105][105],l[105];
int a[105][105];
int h[505];
int num[505];
int cnt=1;
int main(){
char s;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
for (int j=1;j<=m;j++){
cin>>s;
if (s=='H') a[i][j]=1;
l[i]=(l[i]<<1)+a[i][j];
}
}
for (int i=1;i<(1<<m);i++){
if ((((i<<2)|(i>>2)|(i<<1)|(i>>1))&i)==0){
h[++cnt]=i;
int s=i;
while (s){
num[cnt]++;
s -= s & (-s);
}
}
}
for (int i=1;i<=cnt;i++)
if ((h[i]&l[1])==0)
f[1][i][0]=num[i];
for (int i=1;i<=cnt;i++)
if ((h[i]&l[2])==0)
for (int j=1;j<=cnt;j++)
if ((h[i]&h[j])==0&&(h[j]&l[1])==0)
f[2][i][j]=f[1][j][0]+num[i];
for (int i=3;i<=n;i++){
for (int k1=1;k1<=cnt;k1++){
if ((h[k1]&l[i])==0){
for (int k2=1;k2<=cnt;k2++){
if ((h[k1]&h[k2])==0&&(h[k2]&l[i-1])==0){
for (int k3=1;k3<=cnt;k3++){
if ((h[k1]&h[k3])==0&&(h[k2]&h[k3])==0&&(h[k3]&l[i-2])==0){
f[i][k1][k2]=max(f[i][k1][k2],f[i-1][k2][k3]+num[k1]);
}
}
}
}
}
}
}
int ans=0;
for (int i=1;i<=cnt;i++){
for (int j=1;j<=cnt;j++){
ans=max(ans,f[n][i][j]);
}
}
printf("%d\n",ans);
return 0;
}
状压DP详解+题目的更多相关文章
- 状态压缩dp 状压dp 详解
说到状压dp,一般和二进制少不了关系(还常和博弈论结合起来考,这个坑我挖了还没填qwq),二进制是个好东西啊,所以二进制的各种运算是前置知识,不了解的话走下面链接进百度百科 https://baike ...
- 状压DP详解(位运算)
前言: 状压DP是一种非常暴力的做法(有一些可以排除某些状态的除外),例如dp[S][v]中,S可以代表已经访问过的顶点的集合,v可以代表当前所在的顶点为v.S代表的就是一种状态(二进制表示),比如 ...
- 状态压缩动态规划(状压DP)详解
0 引子 不要999,也不要888,只要288,只要288,状压DP带回家.你买不了上当,买不了欺骗.它可以当搜索,也可以卡常数,还可以装B,方式多样,随心搭配,自由多变,一定符合你的口味! 在计算机 ...
- 树形DP详解+题目
关于树形dp 我觉得他和线性dp差不多 总结 最近写了好多树形dp+树形结构的题目,这些题目变化多样能与多种算法结合,但还是有好多规律可以找的. 先说总的规律吧! 一般来说树形dp在设状态转移方程时都 ...
- NOIP2016愤怒的小鸟 [状压dp]
愤怒的小鸟 题目描述 Kiana 最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于 (0,0) 处,每次 Kiana 可以用它向第一象限发射一只红色的小鸟, ...
- zoj3802:easy 2048 again(状压dp)
zoj月赛的题目,非常不错的一个状压dp.. 题目大意是一个一维的2048游戏 只要有相邻的相同就会合并,合并之后会有奖励分数,总共n个,每个都可以取或者不取 问最终得到的最大值 数据范围n<= ...
- 状压dp之二之三 炮兵阵地/玉米田 By cellur925
一.简单的状压dp 玉米田 题目描述 Farmer John has purchased a lush new rectangular pasture composed of M by N (1 ≤ ...
- codeforces#1215E. Marbles(状压DP)
题目大意:给出一个由N个整数组成的序列,通过每次交换相邻的两个数,使这个序列的每个相同的数都相邻.求最小的交换次数. 比如给出序列:1 2 3 2 1 ,那么最终序列应该是 1 1 2 2 3 ,最小 ...
- 【FZYZOJ】愚人节礼物 题解(状压DP)
前言:麻麻我会写状压DP了! ---------------------------- 题目描述 愚人节到了!可爱的UOI小朋友要给孩子们送礼物(汗-原题不是可爱的打败图么= =..).在平面直角坐标 ...
随机推荐
- 痞子衡嵌入式:超级下载算法RT-UFL v1.0在恩智浦MCUXpresso IDE下的使用
痞子衡主导的"学术"项目 <RT-UFL - 一个适用全平台i.MXRT的超级下载算法设计> v1.0 版发布近 4 个月了,部分客户已经在实际项目开发调试中用上了这个 ...
- Redis 深入
1.缓存更新 一般来说缓存的更新有两种情况: 先删除缓存,再更新数据库. 先更新数据库,再删除缓存. 这两种情况在业界,大家对其都有自己的看法.具体怎么使用还得看各自的取舍.当然肯定会有人问为什么要删 ...
- Linux命令查看内存、整体负载、端口查看、进程查看、vim编辑器(3)
一.资源占用命令 1.查看内存(free) free命令默认是以kb为单位显示的. free -m用Mb单位来显示. free -h显示单位 . free -h -s 3 ,每隔三秒刷新一次,如果 ...
- [敏捷软工团队博客]Beta阶段事后分析
设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件要解决的问题是:现在的软工课程的作业分布在博客园.GitHub上,没有一个集成多种功能的一体化 ...
- 21.6.17 test
\(NOI\) 模拟赛. \(T1\) 正解树形DP,由于不是很熟悉概率和期望所以打了个20pts暴力,说不定见多了概率能打出60pts半正解?最后的虚树更不会. \(T2\) 又是概率,还有坐标数量 ...
- 超级好用的轻量级JSON处理命令jq
1 简介 jq是一个轻量级的命令行工具,让你可以非常方便地处理JSON数据,如切分.过滤.映射.转化等,就像sed.awk.grep文本处理三剑客一样.jq是用C写的,没有运行时依赖,你可以直接下载可 ...
- UVM:6.2.3 sequencer 的grab 操作
转载:UVM:6.2.3 sequencer 的grab 操作_tingtang13的博客-CSDN博客 1.grab 比lock 优先级更高. 2.lock 是插到sequencer 仲裁队列的后面 ...
- live555 rtsp直播卡顿马赛克优化
最近搞了个rtsp直播,初步是能用了,但是最终效果不是很好,客户不接受要求我们一定要继续优化. 原因是他们体验的时候发现会概率性出现马赛克和画面卡顿情况,经过我们测试验证,确实是有这个问题存在. 从原 ...
- 面试官:熟悉JS中的new吗?能手写实现吗?
目录 1 new 运算符简介 2 new 究竟干了什么事 3 模拟实现 new 运算符 4 补充 预备知识: 了解原型和原型链 了解this绑定 1 new 运算符简介 MDN文档:new 运算符创建 ...
- java性能优化常用工具jps、jstat、jinfo
jps:虚拟机进程状况工具 jps可以用来查看虚拟机进程,基本等同于ps -ef|grep java #查看jps的使用文档 [root@localhost script]# jps -help us ...