1前言
本文是题解,不会介绍什么是状压dp,萌新请进我主页有介绍状压dp
作者是蒟蒻,提供的思路及标程没有滚动数组等优化,但是足以在洛谷评测机通过
2问题
如下图
翻译一下吧,就是在n*m的方格子里,摆放尽可能多形式如下的十字形物品
00100
00100
11111
00100
00100
可以超出边界,但是互相之间不可以冲突,有些格子不能放,求最多能放多少
这个数据范围,这用背包有后效性,就差把状压dp写题面里了…
3状态设置
我们先考虑直接压,n行m列,但是我们可以发现n非常大,以至于不压m列,只压n行都存不下了
但是m好像小一些
我们舍弃n行,直接用一维数组存n
我们还可以发现,只有上两行的会影响当前行
但是好像压缩三行也有点困难…
因为n作为数组的一维,我们可以只压两行,再用上一行推前两行,这就有递推性质,就这么定了
4属性及转移
属性显然为MAX,求最大值
我们发现,前两行的不同情况都对当前情况有影响
我们枚举三行,不要忘了n
设当前行为i,当前行状态为j,前一行状态为k,前两行状态为l,i二进制位1的个数为count(i)
得状态转移方程dp[i][j][k] = max(dp[i][j][k],dp[i-1][k][l]+count(i));
这时间复杂度大约2^36,能过才怪
5优化
不要忘了不是所有状态均合法,所以我们还有需要特判的步骤没做,在这一步优化吧
我们一步一步优化
优化1
不是所有位置都可以摆放炮兵
我们读入的是字符串,转换为01串,1为山地,然后直接状压
当前状态1为选择,而山地又不能选择,这下可以用与运算了,与出来不为0就跳过,且本方法对三行都适用
优化2
三行中,每个炮兵没有两个在同一列,我们依旧与运算,同上,与出来不为0就跳过,又快了好多
优化3
每一行的炮兵之间间隔至少为2
(1)作者方法
我考虑了lowbit,将每行lowbit算出,相邻之间,设小的为i,大的为j
i左移两位,如果相等或i>j,距离就小于2了
作者是树状数组学魔怔了,还有更快的方法
(2)常规方法
设当前行状态压缩后为i
我们用左移,分别将i左移一位和左移两位,都与一下,不为0就跳过
左移的本质就是将二进制位向左移动,而且是所有二进制位,一次成型,推荐这种方法,常数小
附代码(c++);
#include<bits/stdc++.h>
using namespace std;
const int N = 118,M = (1<<10)+200;
int dp[N][M][M];//本行和上一行,具有递归性质,时间空间乘上两个2^10=2^20
int n,m,ans;
string s;
int a[N];
int lowbit(int x){
return x&-x;
}
bool judge(int x){//优化3
int k = x;
int c1 = lowbit(k),c2;
k-=c1;
while(k!=0){
c2 = lowbit(k);
if((c1<<2)>=c2){
return false;
}
k-=lowbit(k);
swap(c1,c2);
}
return true;
}
int count(int x){
int k = x,sum = 0;
while(k!=0){
sum+=(k&1);
k>>=1;
}
return sum;
}
int main(){
cin>>n>>m;
for(int i = 1;i<=n;i++){
cin>>s;
for(int j = 1;j<=m;j++){//优化1.对地形数组压缩
if(s[j-1]=='H'){
a[i]+=1<<(j-1);
}
}
}
for(int i = 1;i<=n;i++){
for(int j = 0;j<(1<<m);j++){
for(int k = 0;k<(1<<m);k++){
if((!judge(j))||(!judge(k))||((j&k)!=0)||((j&a[i])!=0)||((k&a[i-1])!=0)){//优化2直接体现在if里
continue;
}
for(int l = 0;l<(1<<m);l++){
if(((l&j)!=0)||((l&k)!=0)||(!judge(k))){
continue;
}
dp[i][j][k] = max(dp[i][j][k],dp[i-1][k][l]+count(j));
}
}
}
}
for(int i = 0;i<(1<<m);i++){
for(int j = 0;j<(1<<m);j++){
ans = max(ans,dp[n][i][j]);
}
}
cout<<ans;
return 0;
}
6后记
作者认为,只要位运算学的好,状压dp差不了,高时间复杂度可以用位运算的小常数来平衡
有的位运算甚至能省一轮循环!(如上文优化3中常规方法)
本蒟蒻自己做蓝题很困难,很有可能会产生错误,请各位神犇指点
森林古猿出品,必属精品,请认准CSDN森林古猿1