【POJ1185】炮兵阵地(状压DP)

时间:2024-05-02 02:48:16

题意:

【POJ1185】炮兵阵地(状压DP)

思路:状压DP经典题

可以预处理下每一行内合法的状态,发现很少

所以转移时可以使用状态的编号而不是状态本身

DP时记录前两行状态的编号进行转移和判断

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#define INF 10000
#define MAXK 65
using namespace std;
int dp[][MAXK][MAXK];
int a[MAXK],num[MAXK];
int b[];
int n,m,K;
char s[]; int main()
{
freopen("poj1185.in","r",stdin);
freopen("poj1185.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
scanf("%s",s+);
for(int j=;j<=m;j++)
if(s[j]=='H') b[i]+=(<<(j-));
}
int MAX=(<<m)-;
for(int i=;i<=MAX;i++)
if((!(i&(i<<)))&&(!(i&(i<<))))
{
a[++K]=i;
num[K]=;
int x=i;
while(x>)
{
num[K]+=(x%);
x>>=;
}
} for(int i=;i<=n;i++)
for(int j=;j<=K;j++)
for(int k=;k<=K;k++) dp[i][j][k]=-INF; for(int i=;i<=K;i++)
if(!(b[]&a[i])) dp[][i][]=num[i]; for(int i=;i<=n;i++)
for(int j=;j<=K;j++)
if(!(b[i]&a[j]))
{
for(int k=;k<=K;k++)
if(!(a[j]&a[k]))
{
for(int l=;l<=K;l++)
{
if((a[l]&a[k])||(a[l]&a[j])) continue;
if(dp[i-][k][l]==-INF) continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-][k][l]+num[j]);
}
}
} int ans=;
for(int i=;i<=K;i++)
for(int j=;j<=K;j++) ans=max(ans,dp[n][i][j]);
printf("%d\n",ans);
return ;
}