AcWing 292. 炮兵阵地
原题链接
中等
作者:
总有刁民想害朕
,
2020-03-23 09:50:30
,
所有人可见
,
阅读 734
思路分析:
上一题是只跟上一行状态有关,我们状态定义的时候只需要定义成二维,dp[i][j] 前i行当前第i行状态为j, 这题和上两行状态有关,我们如果定义成二维的(和上面的那个状态定义一样),那么在转移的时候就要从i-1 和 i·2 转移,而我们定义成dp[i][j][k] (前i行,第i行状态为i,第i-1行状态为k),状态只需要从i-1转移过来,所以我们可以定义成三维的,本题空间比较大,这样会mle,所以我们可以才用滚动数组的优化方式,因为只跟i-1的状态有关,所以第一维只要开两个空间就可以了,具体可以看代码
C++ 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 110, M = 12;
int n, m;
int dp[2][1 << M][1 << M];
int g[N];
int num[1 << M];
int main(){
cin >> n >> m;
for(int i = 1;i <= n;++i)
for(int j = 0;j < m;++j){
char x;cin >> x;
if(x == 'P') g[i] |= (1 << (m-j-1));
}
for(int i = 0;i < 1 << m;++i)
for(int j = i; j ;j -= j & -j)
++num[i];
for(int i = 1;i <= n;++i)
for(int j = 0;j < 1 << m;++j) //第i行
if(!(j & (j >> 1)) && !(j & (j >> 2)) && ((j | g[i]) == g[i]))
for(int k = 0;k < 1 << m;++k) //第i-1行
if(!(k & (k << 1)) && !(k & (k << 2)) && !(j & k))
for(int t = 0;t < 1 << m;++t) //第i-2行
if(!(t & (t << 1)) && !(t & (t << 2)) && !(t & k) && !(t & j))
dp[i%2][j][k] = max(dp[i%2][j][k], dp[(i-1)%2][k][t] + num[j]);
int ans = 0;
for(int i = 0;i < 1 << m;++i)
for(int j = 0;j < 1 << m;++j)
ans = max(ans, dp[n%2][i][j]);
cout << ans << endl;
return 0;
}