题目链接:http://poj.org/problem?id=1185
题意:见题面
题解:和做的第一道状压DP(链接:http://blog.csdn.net/haut_ykc/article/details/73136512)基本思路相同。
唯一的不同是这里要求的不是方案数,而是能够放炮兵个数的最大值,因此需要在状压的基础上加上简单的
最大值DP就好了。
DP[ i ][ j ][ k ]:表示第i行状态为k且第i-1行状态为j所放炮兵的的最大值
则状态转移方程为:dp[f][j][k]=max(dp[f][j][k],dp[f-1][i][j]+sum[k]);
(sum数组用来存每种状态所能放的炮兵数量)
详见代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int n,m,cnt,a[105],b[105],dp[105][105][105],sum[105],ans;
char str[105][105];
int judge(int x)
{
if((x&(x<<1)) || (x&(x<<2)))
return 0;
return 1;
}
void init()
{
int i,j;
for(i=0;i<(1<<m);i++)
{
if(judge(i)==0)
continue;
b[++cnt]=i;
for(j=i;j!=0;j=j&(j-1))
sum[cnt]++;
if((i&a[1])==0)
ans=max(ans,sum[cnt]);
}
}
int main(void)
{
int i,j,k,f;
char x;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
scanf(" %c",&x);
if(x=='H')
a[i]+=(1<<(j-1));
}
init();
if(n==1)
{
printf("%d\n",ans);
return 0;
}
for(i=0;i<=cnt;i++)
for(j=0;j<=cnt;j++)
{
if(!(b[i]&b[j]) && !(b[i]&a[1]) && !(b[j]&a[2]))
dp[2][i][j]+=sum[i]+sum[j];
ans=max(ans,dp[2][i][j]);
}
for(f=3;f<=n;f++)
{
for(i=0;i<=cnt;i++)
{
if(a[f-2]&b[i])
continue;
for(j=0;j<=cnt;j++)
{
if((a[f-1]&b[j]) || (b[i]&b[j]))
continue;
for(k=0;k<=cnt;k++)
{
if((a[f]&b[k]) || (b[i]&b[j]) || (b[i]&b[k]) || (b[j]&b[k]))
continue;
dp[f][j][k]=max(dp[f][j][k],dp[f-1][i][j]+sum[k]);
if(f==n)
ans=max(ans,dp[f][j][k]);
}
}
}
}
printf("%d\n",ans);
return 0;
}