炮兵阵地
Description
司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
Input
第一行包含两个由空格分割开的正整数,分别表示N和M;
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
Output
仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。
Sample Input
5 4 PHPP PPHH PPPP PHPP PHHP
Sample Output
6
做的第一题状态压缩型动态规划,先将列数m转化为可行的状态,例如样例中4可以有 2^4个状态态,其中符合题意的只有
0,1,2,4,8,9,转化为2进制数:0000,0001,0010,0100,1000,1001共6种状态
再将地形也转化为二进制数P=0,H=1,第一行就是1011
在求第一行和第二行的dp状态方程的时候要单独初始化
第一行的时候 可以用state[i]&mp[0]可以快速判段此状态和地形会不会冲突
第二行的时候要枚举第一行状态
第三行到第n行只要暴力枚举前两行的状态就可以了
详细
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char mmp[105][12];
int mp[105];
int state[100];
int num[100];
int dp[105][100][100]; //第一个代表行数 第二个代表i-1的状态 第三个代表i-2的状态
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=0; i<n; i++)scanf("%s",mmp[i]);
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(mmp[i][j]=='H')
mp[i]=mp[i]*2+1;
else
mp[i]=mp[i]*2;
}
}
int ans = 0; //计数有几个符合的状态
for(int i=0; i<(1<<m); i++)
{
if((i&(i<<1))||(i&(i<<2)))continue;
int temp=i;
while(temp)
{
num[ans]=num[ans]+(temp&1); //num[ans]=num[ans]+temp&1;这样写是错误的,运算符优先级,被坑死了
temp>>=1;
}
state[ans++]=i;
printf("%d\n",i);
}
for(int i=0; i<ans; i++) //初始化第一行
{
if(mp[0]&state[i])continue;
dp[0][i][0]=num[i];
}
for(int i=0; i<ans; i++)
{
if(state[i]&mp[1])continue;
for(int j=0; j<ans; j++)
{
if(state[j]&mp[0])continue;
if(state[i]&state[j])continue;
dp[1][i][j]=max(dp[1][i][j],dp[0][j][0]+num[i]);
}
}
for(int i=2; i<=n; i++) //2到n行
for(int j=0; j<ans; j++) //枚举i-1行的状态
{
if(state[j]&mp[i-1])continue;
for(int k=0; k<ans; k++) //枚举i-2行的状态
{
if(state[k]&mp[i-2])continue;
for(int now=0; now<ans; now++) //枚举当前第i行的状态
{
if(mp[i]&state[now])continue; //枚举的第i行的状态和地形没有冲突
if(state[j]&state[k])continue; //枚举的i-1行和i-2行没有冲突
if(state[j]&state[now])continue; //枚举的第i行的状态i-1行没有冲突
if(state[k]&state[now])continue; //枚举的第i行的状态i-2行没有冲突
dp[i][now][j]=max(dp[i-1][j][k]+num[now],dp[i][now][j]);
}
}
}
int Max=0;
for(int i=0; i<ans; i++)
for(int j=0; j<ans; j++)
Max=max(dp[n-1][i][j],Max);
printf("%d\n",Max);
return 0;
}