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;
}