pku 1185

http://poj.org/problem?id=1185

Description

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
 

pku 1185

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

分析:这题和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值即可

View Code
#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;
}

你可能感兴趣的:(pku)