题目链接:
http://poj.org/problem?id=1185
题目大意:
中文题。
范围:
N <= 100;M <= 10。
思路:
状压dp。
还是将炮兵摆放的地方设1,不放的地方设0。
因为他对炮兵的攻击范围做了要求,也就是相邻的炮兵位置不能小于2。那么我们就要先筛选出满足这个硬性条件的状态。
然后我们可以发现,对于第i行的状态,与上一行以及上上一行有关。
所以考虑设一个三维dp[i][j][k],代表到第i行时,第i行的状态为j,第i-1行的状态为k时候的最大的可以摆放的数量。
这样我们就可以得到转移方程:dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]),这里num[j]表示在第i行的状态j里面放了多少个炮兵,也就有多少个1。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,kk;
int dp[105][110][110],cur[105],state[110],num[110];
bool ok(int x)
{
if(x&(x<<1))return 0;
if(x&(x<<2))return 0;
return 1;
}
void init()
{
for(int i=0;i<(1<<m);i++)
{
if(ok(i)){state[kk++]=i;
}
}
}
int cal(int x) //计算x的状态下有多少个1;
{
int ans=0;
while(x)
{
ans++;
x&=(x-1);
}
return ans;
}
bool judge(int x,int y)
{
return x&y;
}
int main()
{
char c;
int i,j,k,l;
while(~scanf("%d%d",&n,&m))
{
kk=0;
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
memset(cur,0,sizeof(cur));
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
{
cin>>c;
if(c=='H')cur[i]+=(1<<(m-j));
}
init();
for(i=0;i<kk;i++)
{
num[i]=cal(state[i]);
if(!judge(cur[1],state[i]))
{dp[1][i][0]=num[i]; //边界处理
}
}
for(i=2;i<=n;i++)
{
for(j=0;j<kk;j++)
{
if(judge(cur[i],state[j]))continue;
for(k=0;k<kk;k++)
{
if(judge(state[j],state[k]))continue;
for(l=0;l<kk;l++)
{
if(judge(state[k],state[l]))continue;
if(judge(state[j],state[l]))continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][l]+num[j]);
}
}
}
}
int ans=0;
for(j=0;j<kk;j++)
for(k=0;k<kk;k++)
ans=max(ans,dp[n][j][k]);
printf("%d\n",ans);
}
}