C - 炮兵阵地
Description
司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由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
代码:
1 /* 2 由于每一行的状态要由其前两行来决定所以要定义一个三维数组,dp[i][k][j]=dp[i-1][h][k], 3 第i行的状态为j,第i-1行的状态为k,第i-2行的状态为h。地图中H用1表示,P用0表示,这样会便于后面 4 条件的判断。初始化第一行时dp[1][][j],其前一行的状态用0或1等数表示都行。 5 */ 6 #include<iostream> 7 #include<string> 8 #include<cstdio> 9 #include<cmath> 10 #include<cstring> 11 #include<algorithm> 12 #include<vector> 13 #include<iomanip> 14 #include<queue> 15 #include<stack> 16 using namespace std; 17 int n,m,sn; 18 string s; 19 int mat[105]; //保存地形状态 20 int dp[105][70][70]; 21 int sta[1<<10]; //保存距离大于2的状态 22 int num[1<<10]; //保存每个状态中1,也就是可行解的个数 23 int max(int x,int y) 24 { 25 return x>y?x:y; 26 } 27 void init() 28 { 29 sn=0; 30 for(int j=0;j<(1<<m);j++) 31 if(!(j&(j<<1))&&!(j&(j<<2))) 32 sta[sn++]=j; 33 } 34 int cinit(int x) //此函数用于统计X状态中有几个1,可以自己动手验证一下 35 { 36 int count=0; 37 while(x) 38 { 39 count++; 40 x&=x-1; 41 } 42 return count; 43 } 44 int main() 45 { 46 while(cin>>n>>m) 47 { 48 memset(dp,0,sizeof(dp)); 49 memset(mat,0,sizeof(mat)); 50 for(int i=1;i<=n;i++) 51 { 52 cin>>s; 53 for(int j=m-1;j>=0;j--) 54 { 55 if(s[m-j-1]=='H') 56 mat[i]|=(1<<j); 57 } 58 } 59 init(); 60 for(int j=0;j<sn;j++) 61 { 62 num[j]=cinit(sta[j]); 63 if(mat[1]&sta[j]) continue;//如果第一行的距离大于2的状态sta[j]与本行山地冲突就跳过 64 dp[1][0][j]=num[j]; 65 } 66 for(int j=0;j<sn;j++) 67 { 68 if(mat[2]&sta[j]) continue; 69 for(int k=0;k<sn;k++) 70 { 71 if(sta[k]&sta[j]) continue; 72 dp[2][k][j]=max(dp[2][k][j],dp[1][0][k]+num[j]); 73 } 74 } //初始化第一行与第二行 75 for(int i=3;i<=n;i++) 76 { 77 for(int j=0;j<sn;j++) 78 { 79 if(mat[i]&sta[j]) continue; 80 for(int k=0;k<sn;k++) 81 { 82 if(sta[j]&sta[k]) continue;//第i行的状态不能与第i-1行的状态冲突 83 for(int h=0;h<sn;h++) 84 { 85 if(sta[j]&sta[h]) continue;//第i行的状态不能与第i-2行的状态冲突 86 dp[i][k][j]=max(dp[i][k][j],dp[i-1][h][k]+num[j]); 87 } 88 } 89 } 90 } 91 int ans=0; 92 for(int j=0;j<sn;j++) 93 { 94 for(int k=0;k<sn;k++) 95 ans=max(ans,dp[n][k][j]); 96 } 97 cout<<ans<<endl; 98 } 99 return 0; 100 }