https://www.luogu.org/problemnew/show/P2704
这道题较前面玉米地的题稍微升级了一些,影响范围扩大到2行内
状压DP前面做的工作还是相同的,预处理状态
因为这题n比较大 所以我们直接把合适的状态存起来 后面再用就只循环合法的状态了 不然会爆掉
dp[i][j][k] 三维状态分别表示 第i行的j状态它上一行为k状态时的最大方案数
转移:dp[i][j][h] = max(dp[i][j][h],dp[i-1][h][k] + num[j]);
先预处理1,2行
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 100;
const int M = 1e7 + 100;
const int INF = 0x3f3f3f3f;
const int mod = 100000000;
ll a[105][15],n,m,s[(1<<10)+100],dp[110][(1<<10)+100][(1<<10)+100];
vector<int> v,num;
bool ok[105][(1<<10)+100];
int main()
{
cin >> n >> m;
char c;
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= m;j ++){
cin >> c;
if(c == 'P') a[i][j] = 1;
}
//压缩地图
for(int i = 1;i <= n;i ++)
for(int j = 1;j <= m;j ++)
s[i] = (s[i]<<1) + a[i][j];
//预处理状态
for(int i = 0;i < (1<<m);i ++){
if(((i<<1)&i) == 0 && ((i<<2)&i) == 0){
v.push_back(i);
int tmp = i;
int cnt = 0;
while(tmp){
if(tmp&1) cnt ++;
tmp >>= 1;
}
num.push_back(cnt);
}
}
//预处理第一行
for(int i = 0;i < v.size();i ++){
if((v[i]&s[1]) == v[i]){
ok[1][i] = true;
dp[1][i][0] += num[i];
}
}
//预处理第二行
for(int i = 0;i < v.size();i ++){
if((v[i]&s[2]) == v[i]){
ok[2][i] = true;
for(int j = 0;j < v.size();j ++){
if(ok[1][j] && (v[i]&v[j]) == 0){
dp[2][i][j] = max(dp[2][i][j],dp[1][j][0] + num[i]);
}
}
}
}
for(int i = 3;i <= n;i ++){
for(int j = 0;j < v.size();j ++){
if((v[j]&s[i]) == v[j]){
ok[i][j] = true;
for(int k = 0;k < v.size();k ++){
if(ok[i-2][k] && (v[j]&v[k]) == 0){
for(int h = 0;h < v.size();h ++){
if(ok[i-1][h] && (v[h]&v[k]) == 0 && (v[j]&v[h]) == 0){
dp[i][j][h] = max(dp[i][j][h],dp[i-1][h][k] + num[j]);
}
}
}
}
}
}
}
ll ans = 0;
for(int i = 0;i < v.size();i ++){
for(int j = 0;j < v.size();j ++){
ans = max(ans,dp[n][i][j]);
}
}
cout << ans;
return 0;
}