司令部的将军们打算在NM的网格地图上部署他们的炮兵部队。一个NM的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
Input
第一行包含两个由空格分割开的正整数,分别表示N和M;
接下来的N行,每一行含有连续的M个字符(‘P’或者’H’),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
Output
仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。
Sample Input
5 4
PHPP
PPHH
PPPP
PHPP
PHHP
Sample Output
6
这道题首先使用DP做,需要注意的是,因为每一行的状态更新都是需要知道前面两行的排列的。如果只用dp[n][1<<m]来储存第i行排列为j的时候的最大数量是不行的。因为要调用三成循环去枚举前两行的排列和当前行的排列,而我们的状态转移方程只能写成dp[i][j]=max(dp[i][j],dp[i-1][l]+number[i]).这样的方程保证不了dp[i-1][l]取得最大值时上一层的值,一定是当前行的上上一层的排列。所以应该至少保存两层的信息。dp[i][j][k]:表示第i行为j排列第i-1行为k排列的最大值。我是先分别更新了前两行的dp值(如果行数大于等于2的话),然后再去枚举第i行。
注意。枚举三行的时候一定要从当前行到前面两行依次枚举走。这样才能用到前面已经更新过的值
代码如下。
#include <iostream>
#include <string.h>
int n,m;
using namespace std;
int fit(int a,int b)
{
return (a|b)==b;
}
int no_fight(int pre,int now)
{
if( (pre&now) ==0)
return 1;
return 0;
}
int pick_number(int a)
{
int number=0;
for(int i=0; i<m; i++)
{
if((a&1) ==1)
number++;
a=(a>>1);
}
return number;
}
int main()
{
cin>>n>>m;
int dp[n][1<<m][1<<m];//必须保存两行的信息才可以 dp[i][j][k]i表示第i行j表示第i行的储存信息,j表示第i-1行的储存信息
for(int i=0; i<n; i++)
for(int j=0; j<(1<<m); j++)
for(int k=0; k<(1<<m); k++)
dp[i][j][k]=0;
int Map[n];
memset(Map,0,sizeof(Map));
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
char ch;
cin>>ch;
if(ch=='P') Map[i]=Map[i]|(1<<(m-j-1));
}
}
int state[1<<m];
int k=0;
int max_first=0,max_seconde=0;
int ans=0;
for(int i=0; i<(1<<m); i++)
{
if( ((i>>1)&i)==0 && ((i>>2)&i)==0 )
{
state[k++]=i;
if(fit(i,Map[0])==1)
{
for(int j=0; j<(1<<m); j++)
{
dp[0][i][j]=pick_number(i);
}
max_first=max(max_first,dp[0][i][0]);
}
}
}//每一行不会攻击到自己炮兵的可行数 并且同时更新了第一行的dp值
//再枚举第二行的dp值
if(n>1)
{
for(int i=0; i<k; i++)
{
int row1=state[i];
if(!fit(row1,Map[0]))
continue;
for(int j=0; j<k; j++)
{
int row2=state[j];
if(!fit(row2,Map[1])|| !no_fight(row1,row2))
continue;
dp[1][row2][row1]=pick_number(row1)+pick_number(row2);
max_seconde=max(max_seconde,dp[1][row2][row1]);
}
}
}
else
{
ans=max_first;
cout<<ans;
return 0;
}
//再枚举第i行的所有情况
if(n>2)
{
for(int i=2; i<n; i++)
{
for(int x3=0; x3<k; x3++)
{
int row3=state[x3];
if(!fit(row3,Map[i]))
continue;
for(int x2=0; x2<k; x2++)
{
int row2=state[x2];
if(!fit(row2,Map[i-1])|| !no_fight(row2,row3))
continue;
for(int x1=0; x1<k; x1++)
{
int row1=state[x1];
if(!fit(row1,Map[i-2]) || !no_fight(row1,row3) || !no_fight(row1,row2))
continue;
dp[i][row3][row2]=max(dp[i][row3][row2],dp[i-1][row2][row1]+pick_number(row3));
if(i==n-1)
{
ans=max(ans,dp[i][row3][row2]);
}
}
}
}
}
}
else
{
ans=max_seconde;
cout<<ans<<endl;
return 0;
}
cout<<ans;
return 0;
}
——— 自己选的路,跪着也要走完。