http://poj.org/problem?id=1185
Description
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
分析:这题和HDU 3254属于同一类题目,都是二进制状态压缩DP。不同的是,这题要难一些,同样的,刚刚开始我们先预处理每一行的可行状态,HDU3254只和前面一行构成矛盾关系,这一题的难点就是在于它的每一行和前面两行都构成了矛盾关系。此时二维数组便不够用了,应该使用三维数组dp[i][j][k]表示第i行取第j中状态并且第i-1行取第k中状态的最大部队摆放数目。
由于每一行都和前两行有关系,那么我们就要特殊处理第一行和第二行
对于第一行:dp[1][i][0]=i状态摆放的炮兵数目
对于第二行:dp[2][i][k]先判断state[2][i]和state[1][k]是否矛盾,不矛盾的话dp[2][i][k]=max(dp[2][i][k],dp[1][k][0]+i状态的炮兵数目)
对于其他:dp[i][j][k],先判断state[i][j]和state[i-1][k]是否矛盾,不矛盾的话再判断state[i][j]和state[i-2][p]是否矛盾,如果都不矛盾的话,则
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][p]+i状态的炮兵数目) //由于dp[i-1][k][p]一定是从上面得到的合法数据,且一定会大于等于i-2行的最大值,所以不需要再用i和i-2进行比较了
最后,我们输出最后一行的最大dp值即可
#include<iostream>
#include<string>
#include<vector>
using namespace std;
#define maxn 70
int dp[101][maxn+1][maxn+1];
int n,m;
vector<int>state[101];
int lowbit(int x) //返回第一个不为0的二进制
{
return x&(-x);
}
int max(int a,int b)
{
return a>b?a:b;
}
void getstate(int i,int temp) //计算每行的合法状态
{
int j;
for(j=0;j<(1<<m);j++)
{
if((j<<1)&j | (j>>1)&j | (j<<2)&j | (j>>2)&j)
continue;
if(j&temp)
continue;
state[i].push_back(j);
}
}
int num(int temp) //计算某一个状态有多少个1,即排列了多少炮兵
{
int ans=0;
while(temp)
{
temp-=lowbit(temp);
ans++;
}
return ans;
}
void solve()
{
int i,j,k,p;
memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
{
for(j=0;j<state[i].size();j++)
{
int nn=num(state[i][j]);
if(i==1) //特殊处理第一行
{
dp[i][j][0]=nn;
}
else if(i==2) //特殊处理第二行
{
for(k=0;k<state[1].size();k++)
{
if(state[i][j]&state[1][k])
continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][0]+nn);
}
}
else
{
for(k=0;k<state[i-1].size();k++)
{
if(state[i][j] & state[i-1][k])
continue;
for(p=0;p<state[i-2].size();p++)
{
if(state[i][j] & state[i-2][p])
continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][p]+nn);
}
}
}
}
}
int ans=0;
if(n==1)
{
for(i=0;i<state[n].size();i++)
{
ans=max(ans,dp[n][i][0]);
}
}
else
{
for(i=0;i<state[n].size();i++)
{
for(j=0;j<state[n-1].size();j++)
{
ans=max(ans,dp[n][i][j]);
}
}
}
printf("%d\n",ans);
}
int main()
{
char a[15];
int i,j,temp;
freopen("D:\\in.txt","r",stdin);
while(scanf("%d%d",&n,&m)!=EOF)
{
scanf("%*c");
for(i=1;i<=n;i++)
{
state[i].clear();
temp=0;
scanf("%s",a);
for(j=0;j<m;j++)
{
if(a[j]=='P')
temp=temp*2+0;
else
temp=temp*2+1;
}
getstate(i,temp);
}
solve();
}
return 0;
}